Merge remote-tracking branch 'origin/main' into feature/individual-publication-modals

This commit is contained in:
Jacob Overgaard
2024-03-13 17:03:36 +01:00
73 changed files with 374 additions and 209 deletions

View File

@@ -284,6 +284,7 @@ export type { PagedProblemDetailsModel } from './models/PagedProblemDetailsModel
export type { PagedRedirectUrlResponseModel } from './models/PagedRedirectUrlResponseModel';
export type { PagedRelationItemResponseModel } from './models/PagedRelationItemResponseModel';
export type { PagedRelationResponseModel } from './models/PagedRelationResponseModel';
export type { PagedRelationTypeTreeItemResponseModel } from './models/PagedRelationTypeTreeItemResponseModel';
export type { PagedSavedLogSearchResponseModel } from './models/PagedSavedLogSearchResponseModel';
export type { PagedSearcherResponseModel } from './models/PagedSearcherResponseModel';
export type { PagedSearchResultResponseModel } from './models/PagedSearchResultResponseModel';
@@ -291,6 +292,7 @@ export type { PagedTagResponseModel } from './models/PagedTagResponseModel';
export type { PagedTelemetryResponseModel } from './models/PagedTelemetryResponseModel';
export type { PagedUserGroupResponseModel } from './models/PagedUserGroupResponseModel';
export type { PagedUserResponseModel } from './models/PagedUserResponseModel';
export type { PagedWebhookResponseModel } from './models/PagedWebhookResponseModel';
export type { PartialViewFolderResponseModel } from './models/PartialViewFolderResponseModel';
export type { PartialViewItemResponseModel } from './models/PartialViewItemResponseModel';
export type { PartialViewResponseModel } from './models/PartialViewResponseModel';
@@ -320,6 +322,7 @@ export type { RelationResponseModel } from './models/RelationResponseModel';
export type { RelationTypeBaseModel } from './models/RelationTypeBaseModel';
export type { RelationTypeItemResponseModel } from './models/RelationTypeItemResponseModel';
export type { RelationTypeResponseModel } from './models/RelationTypeResponseModel';
export type { RelationTypeTreeItemResponseModel } from './models/RelationTypeTreeItemResponseModel';
export type { RenamePartialViewRequestModel } from './models/RenamePartialViewRequestModel';
export type { RenameScriptRequestModel } from './models/RenameScriptRequestModel';
export type { RenameStylesheetRequestModel } from './models/RenameStylesheetRequestModel';

View File

@@ -6,7 +6,6 @@
import type { ReferenceByIdModel } from './ReferenceByIdModel';
export type ContentTreeItemResponseModel = {
type: string;
hasChildren: boolean;
parent?: ReferenceByIdModel | null;
noAccess: boolean;

View File

@@ -9,9 +9,10 @@ import type { DocumentTypeTreeItemResponseModel } from './DocumentTypeTreeItemRe
import type { FolderTreeItemResponseModel } from './FolderTreeItemResponseModel';
import type { MediaTypeTreeItemResponseModel } from './MediaTypeTreeItemResponseModel';
import type { NamedEntityTreeItemResponseModel } from './NamedEntityTreeItemResponseModel';
import type { RelationTypeTreeItemResponseModel } from './RelationTypeTreeItemResponseModel';
export type PagedNamedEntityTreeItemResponseModel = {
total: number;
items: Array<(NamedEntityTreeItemResponseModel | DataTypeTreeItemResponseModel | DocumentBlueprintTreeItemResponseModel | DocumentTypeTreeItemResponseModel | FolderTreeItemResponseModel | MediaTypeTreeItemResponseModel)>;
items: Array<(NamedEntityTreeItemResponseModel | DataTypeTreeItemResponseModel | DocumentBlueprintTreeItemResponseModel | DocumentTypeTreeItemResponseModel | FolderTreeItemResponseModel | MediaTypeTreeItemResponseModel | RelationTypeTreeItemResponseModel)>;
};

View File

@@ -0,0 +1,12 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { RelationTypeTreeItemResponseModel } from './RelationTypeTreeItemResponseModel';
export type PagedRelationTypeTreeItemResponseModel = {
total: number;
items: Array<RelationTypeTreeItemResponseModel>;
};

View File

@@ -0,0 +1,12 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { WebhookResponseModel } from './WebhookResponseModel';
export type PagedWebhookResponseModel = {
total: number;
items: Array<WebhookResponseModel>;
};

View File

@@ -5,5 +5,7 @@
import type { NamedItemResponseModelBaseModel } from './NamedItemResponseModelBaseModel';
export type RelationTypeItemResponseModel = NamedItemResponseModelBaseModel;
export type RelationTypeItemResponseModel = (NamedItemResponseModelBaseModel & {
isDeletable: boolean;
});

View File

@@ -9,7 +9,7 @@ export type RelationTypeResponseModel = (RelationTypeBaseModel & {
id: string;
alias?: string | null;
path: string;
isSystemRelationType: boolean;
isDeletable: boolean;
parentObjectTypeName?: string | null;
childObjectTypeName?: string | null;
});

View File

@@ -0,0 +1,11 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { NamedEntityTreeItemResponseModel } from './NamedEntityTreeItemResponseModel';
export type RelationTypeTreeItemResponseModel = (NamedEntityTreeItemResponseModel & {
isDeletable: boolean;
});

View File

@@ -4,7 +4,6 @@
/* eslint-disable */
export type TreeItemPresentationModel = {
type: string;
hasChildren: boolean;
};

View File

@@ -3,7 +3,7 @@
/* tslint:disable */
/* eslint-disable */
import type { CreateRelationTypeRequestModel } from '../models/CreateRelationTypeRequestModel';
import type { PagedNamedEntityTreeItemResponseModel } from '../models/PagedNamedEntityTreeItemResponseModel';
import type { PagedRelationTypeTreeItemResponseModel } from '../models/PagedRelationTypeTreeItemResponseModel';
import type { RelationTypeItemResponseModel } from '../models/RelationTypeItemResponseModel';
import type { RelationTypeResponseModel } from '../models/RelationTypeResponseModel';
import type { UpdateRelationTypeRequestModel } from '../models/UpdateRelationTypeRequestModel';
@@ -130,7 +130,7 @@ export class RelationTypeResource {
}
/**
* @returns PagedNamedEntityTreeItemResponseModel Success
* @returns PagedRelationTypeTreeItemResponseModel Success
* @throws ApiError
*/
public static getTreeRelationTypeRoot({
@@ -139,7 +139,7 @@ export class RelationTypeResource {
}: {
skip?: number,
take?: number,
}): CancelablePromise<PagedNamedEntityTreeItemResponseModel> {
}): CancelablePromise<PagedRelationTypeTreeItemResponseModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/tree/relation-type/root',

View File

@@ -3,6 +3,7 @@
/* tslint:disable */
/* eslint-disable */
import type { CreateWebhookRequestModel } from '../models/CreateWebhookRequestModel';
import type { PagedWebhookResponseModel } from '../models/PagedWebhookResponseModel';
import type { UpdateWebhookRequestModel } from '../models/UpdateWebhookRequestModel';
import type { WebhookItemResponseModel } from '../models/WebhookItemResponseModel';
import type { WebhookResponseModel } from '../models/WebhookResponseModel';
@@ -13,6 +14,30 @@ import { request as __request } from '../core/request';
export class WebhookResource {
/**
* @returns PagedWebhookResponseModel Success
* @throws ApiError
*/
public static getWebhook({
skip,
take = 100,
}: {
skip?: number,
take?: number,
}): CancelablePromise<PagedWebhookResponseModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/webhook',
query: {
'skip': skip,
'take': take,
},
errors: {
401: `The resource is protected and requires an authentication token`,
},
});
}
/**
* @returns string Created
* @throws ApiError

View File

@@ -0,0 +1,3 @@
export function assignToFrozenObject<T extends object>(target: T, source: Partial<T>): T {
return Object.assign(Object.create(Object.getPrototypeOf(target)), target, source);
}

View File

@@ -1,4 +1,5 @@
export * from './append-to-frozen-array.function.js';
export * from './assign-to-frozen-object.function.js';
export * from './create-observable-part.function.js';
export * from './deep-freeze.function.js';
export * from './default-memoization.function.js';

View File

@@ -4,9 +4,7 @@ import type {
DataTypeTreeItemResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
type UmbMockDataTypeModelHack = DataTypeResponseModel & DataTypeTreeItemResponseModel & DataTypeItemResponseModel;
export interface UmbMockDataTypeModel extends Omit<UmbMockDataTypeModelHack, 'type'> {}
export type UmbMockDataTypeModel = DataTypeResponseModel & DataTypeTreeItemResponseModel & DataTypeItemResponseModel;
export const data: Array<UmbMockDataTypeModel> = [
{

View File

@@ -5,13 +5,11 @@ import type {
NamedEntityTreeItemResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
type UmbMockDictionaryModelHack = DictionaryItemResponseModel &
export type UmbMockDictionaryModel = DictionaryItemResponseModel &
NamedEntityTreeItemResponseModel &
DictionaryItemItemResponseModel &
DictionaryOverviewResponseModel;
export interface UmbMockDictionaryModel extends Omit<UmbMockDictionaryModelHack, 'type'> {}
export const data: Array<UmbMockDictionaryModel> = [
{
name: 'Hello',

View File

@@ -38,7 +38,7 @@ export class UmbDictionaryMockDB extends UmbEntityMockDbBase<UmbMockDictionaryMo
}
}
const treeItemMapper = (model: UmbMockDictionaryModel): Omit<NamedEntityTreeItemResponseModel, 'type'> => {
const treeItemMapper = (model: UmbMockDictionaryModel): NamedEntityTreeItemResponseModel => {
return {
name: model.name,
id: model.id,

View File

@@ -5,12 +5,10 @@ import type {
DocumentTypeTreeItemResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
type UmbMockDocumentTypeModelHack = DocumentTypeResponseModel &
export type UmbMockDocumentTypeModel = DocumentTypeResponseModel &
DocumentTypeTreeItemResponseModel &
DocumentTypeItemResponseModel;
export interface UmbMockDocumentTypeModel extends Omit<UmbMockDocumentTypeModelHack, 'type'> {}
export const data: Array<UmbMockDocumentTypeModel> = [
{
allowedTemplates: [],

View File

@@ -122,9 +122,7 @@ const documentTypeDetailMapper = (item: UmbMockDocumentTypeModel): DocumentTypeR
};
};
const documentTypeTreeItemMapper = (
item: UmbMockDocumentTypeModel,
): Omit<DocumentTypeTreeItemResponseModel, 'type'> => {
const documentTypeTreeItemMapper = (item: UmbMockDocumentTypeModel): DocumentTypeTreeItemResponseModel => {
return {
name: item.name,
hasChildren: item.hasChildren,

View File

@@ -5,9 +5,7 @@ import type {
} from '@umbraco-cms/backoffice/external/backend-api';
import { DocumentVariantStateModel } from '@umbraco-cms/backoffice/external/backend-api';
type UmbMockDocumentTypeModelHack = DocumentResponseModel & DocumentTreeItemResponseModel & DocumentItemResponseModel;
export interface UmbMockDocumentModel extends Omit<UmbMockDocumentTypeModelHack, 'type'> {}
export type UmbMockDocumentModel = DocumentResponseModel & DocumentTreeItemResponseModel & DocumentItemResponseModel;
export const data: Array<UmbMockDocumentModel> = [
{

View File

@@ -41,7 +41,7 @@ export class UmbDocumentMockDB extends UmbEntityMockDbBase<UmbMockDocumentModel>
}
}
const treeItemMapper = (model: UmbMockDocumentModel): Omit<DocumentTreeItemResponseModel, 'type'> => {
const treeItemMapper = (model: UmbMockDocumentModel): DocumentTreeItemResponseModel => {
const documentType = umbDocumentTypeMockDb.read(model.documentType.id);
if (!documentType) throw new Error(`Document type with id ${model.documentType.id} not found`);

View File

@@ -14,7 +14,7 @@ class UmbLogViewerSearchesData extends UmbMockDBBase<SavedLogSearchResponseModel
// skip can be number or null
getSavedSearches(skip = 0, take = this.data.length): Array<SavedLogSearchResponseModel> {
return this.data.slice(skip, take);
return this.data.slice(skip, take + skip);
}
getByName(name: string) {
@@ -29,7 +29,7 @@ class UmbLogViewerTemplatesData extends UmbMockDBBase<LogTemplateResponseModel>
// skip can be number or null
getTemplates(skip = 0, take = this.data.length): Array<LogTemplateResponseModel> {
return this.data.slice(skip, take);
return this.data.slice(skip, take + skip);
}
}

View File

@@ -4,9 +4,9 @@ import type {
MediaTypeTreeItemResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
type UmbMockMediaTypeModelHack = MediaTypeResponseModel & MediaTypeTreeItemResponseModel & MediaTypeItemResponseModel;
export interface UmbMockMediaTypeModel extends Omit<UmbMockMediaTypeModelHack, 'type'> {}
export type UmbMockMediaTypeModel = MediaTypeResponseModel &
MediaTypeTreeItemResponseModel &
MediaTypeItemResponseModel;
export const data: Array<UmbMockMediaTypeModel> = [
{
@@ -91,9 +91,7 @@ export const data: Array<UmbMockMediaTypeModel> = [
variesByCulture: false,
variesBySegment: false,
isElement: false,
allowedMediaTypes: [
{ mediaType: { id: 'media-type-1-id' }, sortOrder: 0 },
],
allowedMediaTypes: [{ mediaType: { id: 'media-type-1-id' }, sortOrder: 0 }],
compositions: [],
isFolder: false,
hasChildren: false,

View File

@@ -110,7 +110,7 @@ const mediaTypeDetailMapper = (item: UmbMockMediaTypeModel): MediaTypeResponseMo
};
};
const mediaTypeTreeItemMapper = (item: UmbMockMediaTypeModel): Omit<MediaTypeTreeItemResponseModel, 'type'> => {
const mediaTypeTreeItemMapper = (item: UmbMockMediaTypeModel): MediaTypeTreeItemResponseModel => {
return {
name: item.name,
hasChildren: item.hasChildren,

View File

@@ -4,9 +4,7 @@ import type {
MediaTreeItemResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
type UmbMockMediaModelHack = MediaResponseModel & MediaTreeItemResponseModel & MediaItemResponseModel;
export interface UmbMockMediaModel extends Omit<UmbMockMediaModelHack, 'type'> {}
export type UmbMockMediaModel = MediaResponseModel & MediaTreeItemResponseModel & MediaItemResponseModel;
export const data: Array<UmbMockMediaModel> = [
{

View File

@@ -28,7 +28,7 @@ export class UmbMediaMockDB extends UmbEntityMockDbBase<UmbMockMediaModel> {
}
}
const treeItemMapper = (model: UmbMockMediaModel): Omit<MediaTreeItemResponseModel, 'type'> => {
const treeItemMapper = (model: UmbMockMediaModel): MediaTreeItemResponseModel => {
const mediaType = umbMediaTypeMockDb.read(model.mediaType.id);
if (!mediaType) throw new Error(`Media type with id ${model.mediaType.id} not found`);

View File

@@ -5,12 +5,10 @@ import type {
PartialViewSnippetResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
type UmbMockPartialViewModelHack = PartialViewResponseModel &
export type UmbMockPartialViewModel = PartialViewResponseModel &
FileSystemTreeItemPresentationModel &
PartialViewItemResponseModel;
export interface UmbMockPartialViewModel extends Omit<UmbMockPartialViewModelHack, 'type' | 'icon'> {}
export const data: Array<UmbMockPartialViewModel> = [
{
name: 'blockgrid',

View File

@@ -12,7 +12,7 @@ export const data: Array<RelationTypeResponseModel> = [
alias: 'relateDocumentOnCopy',
name: 'Relate Document On Copy',
path: '',
isSystemRelationType: true,
isDeletable: true,
isBidirectional: false,
isDependency: false,
parentObjectType: 'Document',
@@ -25,7 +25,7 @@ export const data: Array<RelationTypeResponseModel> = [
alias: 'relateParentDocumentOnDelete',
name: 'Relate Parent Document On Delete',
path: '',
isSystemRelationType: true,
isDeletable: true,
isBidirectional: false,
isDependency: false,
parentObjectType: 'Document',
@@ -38,7 +38,7 @@ export const data: Array<RelationTypeResponseModel> = [
alias: 'relateParentMediaFolderOnDelete',
name: 'Relate Parent Media Folder On Delete',
path: '',
isSystemRelationType: true,
isDeletable: true,
isBidirectional: false,
isDependency: false,
parentObjectType: 'Document',
@@ -51,7 +51,7 @@ export const data: Array<RelationTypeResponseModel> = [
alias: 'relatedMedia',
name: 'Related Media',
path: '',
isSystemRelationType: true,
isDeletable: true,
isBidirectional: false,
isDependency: false,
parentObjectType: 'Document',
@@ -64,7 +64,7 @@ export const data: Array<RelationTypeResponseModel> = [
alias: 'relatedDocument',
name: 'Related Document',
path: '',
isSystemRelationType: true,
isDeletable: true,
isBidirectional: false,
isDependency: false,
parentObjectType: 'Document',
@@ -79,7 +79,6 @@ export const treeData: Array<NamedEntityTreeItemResponseModel> = [
id: 'e0d39ff5-71d8-453f-b682-9d8d31ee5e06',
parent: null,
name: 'Relate Document On Copy',
type: 'relation-type',
hasChildren: false,
},
{
@@ -87,28 +86,24 @@ export const treeData: Array<NamedEntityTreeItemResponseModel> = [
parent: null,
name: 'Relate Parent Document On Delete',
type: 'relation-type',
hasChildren: false,
},
{
id: '6f9b800c-762c-42d4-85d9-bf40a77d689e',
parent: null,
name: 'Relate Parent Media Folder On Delete',
type: 'relation-type',
hasChildren: false,
},
{
id: 'd421727d-43de-4205-b4c6-037404f309ad',
parent: null,
name: 'Related Media',
type: 'relation-type',
hasChildren: false,
},
{
id: 'e9a0a28e-2d5b-4229-ac00-66f2df230513',
parent: null,
name: 'Related Document',
type: 'relation-type',
hasChildren: false,
},
];

View File

@@ -4,9 +4,7 @@ import type {
ScriptResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
type UmbMockScriptModelHack = ScriptResponseModel & FileSystemTreeItemPresentationModel & ScriptItemResponseModel;
export interface UmbMockScriptModel extends Omit<UmbMockScriptModelHack, 'type' | 'icon'> {}
export type UmbMockScriptModel = ScriptResponseModel & FileSystemTreeItemPresentationModel & ScriptItemResponseModel;
export const data: Array<UmbMockScriptModel> = [
{

View File

@@ -3,8 +3,7 @@ import type {
StaticFileItemResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
type UmbMockStaticFileModelHack = StaticFileItemResponseModel & FileSystemTreeItemPresentationModel;
export interface UmbMockStaticFileModel extends Omit<UmbMockStaticFileModelHack, 'type'> {}
export type UmbMockStaticFileModel = StaticFileItemResponseModel & FileSystemTreeItemPresentationModel;
export const data: Array<UmbMockStaticFileModel> = [
{

View File

@@ -4,12 +4,10 @@ import type {
StylesheetResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
type UmbMockStylesheetModelHack = StylesheetResponseModel &
export type UmbMockStylesheetModel = StylesheetResponseModel &
FileSystemTreeItemPresentationModel &
StylesheetItemResponseModel;
export interface UmbMockStylesheetModel extends Omit<UmbMockStylesheetModelHack, 'type' | 'icon'> {}
export const data: Array<UmbMockStylesheetModel> = [
{
name: 'Stylesheet File 1.css',

View File

@@ -7,9 +7,7 @@ import type {
} from '@umbraco-cms/backoffice/external/backend-api';
import { TemplateQueryPropertyTypeModel, OperatorModel } from '@umbraco-cms/backoffice/external/backend-api';
type UmbMockTemplateModelHack = TemplateResponseModel & NamedEntityTreeItemResponseModel & TemplateItemResponseModel;
export interface UmbMockTemplateModel extends Omit<UmbMockTemplateModelHack, 'type'> {}
export type UmbMockTemplateModel = TemplateResponseModel & NamedEntityTreeItemResponseModel & TemplateItemResponseModel;
export const data: Array<UmbMockTemplateModel> = [
{

View File

@@ -7,7 +7,6 @@ import type {
export const createEntityTreeItem = (item: any): NamedEntityTreeItemResponseModel => {
return {
name: item.name,
type: item.type,
hasChildren: item.hasChildren,
id: item.id,
parent: item.parent,
@@ -21,7 +20,7 @@ export const folderTreeItemMapper = (item: any): FolderTreeItemResponseModel =>
};
};
export const createFileSystemTreeItem = (item: any): Omit<FileSystemTreeItemPresentationModel, 'type'> => {
export const createFileSystemTreeItem = (item: any): FileSystemTreeItemPresentationModel => {
return {
path: item.path,
parent: item.parent ?? null,

View File

@@ -6,7 +6,7 @@ import type {
UpdateFolderResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
export class UmbMockEntityFolderManager<MockItemType extends Omit<FolderTreeItemResponseModel, 'type'>> {
export class UmbMockEntityFolderManager<MockItemType extends FolderTreeItemResponseModel> {
#db: UmbEntityMockDbBase<MockItemType>;
#createMockFolderMapper: (request: CreateFolderRequestModel) => MockItemType;

View File

@@ -2,9 +2,7 @@ import { UmbEntityMockDbBase } from './entity-base.js';
import { UmbMockEntityTreeManager } from './entity-tree.manager.js';
import type { ContentTreeItemResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
export class UmbEntityRecycleBin<
MockType extends Omit<ContentTreeItemResponseModel, 'type'>,
> extends UmbEntityMockDbBase<MockType> {
export class UmbEntityRecycleBin<MockType extends ContentTreeItemResponseModel> extends UmbEntityMockDbBase<MockType> {
tree;
constructor(data: Array<MockType>, treeItemMapper: (model: MockType) => any) {

View File

@@ -3,7 +3,7 @@ import type { UmbEntityMockDbBase } from './entity-base.js';
import { UmbId } from '@umbraco-cms/backoffice/id';
import type { EntityTreeItemResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
export class UmbMockEntityTreeManager<T extends Omit<EntityTreeItemResponseModel, 'type'>> {
export class UmbMockEntityTreeManager<T extends EntityTreeItemResponseModel> {
#db: UmbEntityMockDbBase<T>;
#treeItemMapper: (item: T) => any;

View File

@@ -3,7 +3,7 @@ import { createFileSystemTreeItem } from '../../utils.js';
import { pagedResult } from '../paged-result.js';
import type { FileSystemTreeItemPresentationModel } from '@umbraco-cms/backoffice/external/backend-api';
export class UmbMockFileSystemTreeManager<T extends Omit<FileSystemTreeItemPresentationModel, 'type'>> {
export class UmbMockFileSystemTreeManager<T extends FileSystemTreeItemPresentationModel> {
#db: UmbMockDBBase<T>;
constructor(mockDb: UmbMockDBBase<T>) {
@@ -11,7 +11,7 @@ export class UmbMockFileSystemTreeManager<T extends Omit<FileSystemTreeItemPrese
}
getRoot({ skip = 0, take = 100 }: { skip?: number; take?: number } = {}): {
items: Array<Omit<FileSystemTreeItemPresentationModel, 'type'>>;
items: Array<FileSystemTreeItemPresentationModel>;
total: number;
} {
const items = this.#db.getAll().filter((item) => item.parent === null);
@@ -19,7 +19,7 @@ export class UmbMockFileSystemTreeManager<T extends Omit<FileSystemTreeItemPrese
}
getChildrenOf({ parentPath, skip = 0, take = 100 }: { parentPath: string; skip?: number; take?: number }): {
items: Array<Omit<FileSystemTreeItemPresentationModel, 'type'>>;
items: Array<FileSystemTreeItemPresentationModel>;
total: number;
} {
const items = this.#db.getAll().filter((item) => item.parent?.path === parentPath);

View File

@@ -14,7 +14,7 @@ export const handlers = [
const items = umbLogViewerData.searches.getSavedSearches(skipNumber, takeNumber);
const response = {
total: items.length,
total: umbLogViewerData.searches.total,
items,
};
@@ -57,7 +57,7 @@ export const handlers = [
return res(ctx.delay(), ctx.status(200), ctx.json(response));
}),
//#endregion
//#region Logs
rest.get(umbracoPath('/log-viewer/level'), (req, res, ctx) => {
return res(ctx.delay(), ctx.status(200), ctx.json(umbLogViewerData.logLevels));

View File

@@ -85,7 +85,7 @@ export class UmbCollectionViewBundleElement extends UmbLitElement {
}
#renderItemDisplay(view: ManifestCollectionView) {
return html`<umb-icon name=${view.meta.icon}></u-icon>`;
return html`<umb-icon name=${view.meta.icon}></umb-icon>`;
}
static styles = [

View File

@@ -69,7 +69,7 @@ export class UmbCollectionDefaultElement extends UmbLitElement {
}
protected renderSelectionActions() {
return html`<umb-collection-selection-actions slot="footer-info"></umb-collection-selection-actions>`;
return html`<umb-collection-selection-actions slot="footer"></umb-collection-selection-actions>`;
}
static styles = [

View File

@@ -161,6 +161,7 @@ export class UmbExtensionWithApiSlotElement extends UmbLitElement {
undefined, // We can leave the alias to undefined, as we destroy this our selfs.
this.defaultElement,
);
this.#extensionsController.apiProperties = this.#apiProps;
this.#extensionsController.elementProperties = this.#elProps;
}
}

View File

@@ -26,7 +26,7 @@ export class UmbIconPickerModalElement extends UmbModalBaseElement<UmbIconPicker
@state()
private _currentAlias = 'text';
#changeIcon(e: { target: HTMLInputElement; type: any; key: unknown }) {
#changeIcon(e: { target: HTMLInputElement; type: string; key: unknown }) {
if (e.type == 'click' || (e.type == 'keyup' && e.key == 'Enter')) {
this.modalContext?.updateValue({ icon: e.target.id });
}
@@ -34,7 +34,9 @@ export class UmbIconPickerModalElement extends UmbModalBaseElement<UmbIconPicker
#filterIcons(e: { target: HTMLInputElement }) {
if (e.target.value) {
this._iconListFiltered = this._iconList.filter((icon) => icon.name.includes(e.target.value));
this._iconListFiltered = this._iconList.filter((icon) =>
icon.name.toLowerCase().includes(e.target.value.toLowerCase()),
);
} else {
this._iconListFiltered = this._iconList;
}

View File

@@ -9,7 +9,7 @@ import { UmbArrayState, UmbBooleanState } from '@umbraco-cms/backoffice/observab
* @class UmbSelectionManager
*/
export class UmbSelectionManager<ValueType extends string | null = string | null> extends UmbControllerBase {
#selectable = new UmbBooleanState(false);
#selectable = new UmbBooleanState(true);
public readonly selectable = this.#selectable.asObservable();
#selection = new UmbArrayState(<Array<ValueType>>[], (x) => x);

View File

@@ -111,7 +111,7 @@ export class UmbCreateDocumentCollectionActionElement extends UmbLitElement {
const label = this.manifest?.meta.label ?? this.localize.term('general_create');
return html`
<uui-button popovertarget="collection-action-menu-popover" label=${label}>
<uui-button popovertarget="collection-action-menu-popover" label=${label} color="default" look="outline">
${label}
<uui-symbol-expand .open=${this._popoverOpen}></uui-symbol-expand>
</uui-button>

View File

@@ -10,6 +10,5 @@ export class UmbDocumentCollectionContext extends UmbDefaultCollectionContext<
constructor(host: UmbControllerHost) {
super(host, UMB_DOCUMENT_TABLE_COLLECTION_VIEW_ALIAS);
this.selection.setSelectable(true);
}
}

View File

@@ -1,12 +1,15 @@
import type { UmbDocumentCollectionFilterModel } from '../types.js';
import { UmbDocumentCollectionServerDataSource } from './document-collection.server.data-source.js';
import { UmbRepositoryBase } from '@umbraco-cms/backoffice/repository';
import type { UmbCollectionRepository } from '@umbraco-cms/backoffice/collection';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
export class UmbDocumentCollectionRepository implements UmbCollectionRepository {
export class UmbDocumentCollectionRepository extends UmbRepositoryBase implements UmbCollectionRepository {
#collectionSource: UmbDocumentCollectionServerDataSource;
constructor(host: UmbControllerHost) {
super(host);
this.#collectionSource = new UmbDocumentCollectionServerDataSource(host);
}

View File

@@ -17,13 +17,9 @@ export class UmbDocumentCollectionServerDataSource implements UmbCollectionDataS
throw new Error('Unique ID is required to fetch a collection.');
}
if (!query.dataTypeId) {
throw new Error('Data type ID is required to fetch a collection.');
}
const params = {
id: query.unique,
dataTypeId: query.dataTypeId,
dataTypeId: query.dataTypeId ?? '',
orderBy: query.orderBy ?? 'updateDate',
orderCulture: query.orderCulture ?? 'en-US',
orderDirection: query.orderDirection === 'asc' ? DirectionModel.ASCENDING : DirectionModel.DESCENDING,

View File

@@ -1,11 +1,11 @@
import { getPropertyValueByAlias } from '../index.js';
import type { UmbCollectionColumnConfiguration } from '../../../../../core/collection/types.js';
import type { UmbDocumentCollectionFilterModel, UmbDocumentCollectionItemModel } from '../../types.js';
import type { UmbDocumentCollectionItemModel } from '../../types.js';
import type { UmbDocumentCollectionContext } from '../../document-collection.context.js';
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UMB_DEFAULT_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/collection';
import type { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collection';
import type {
UmbTableColumn,
UmbTableConfig,
@@ -62,7 +62,7 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement {
@state()
private _skip: number = 0;
#collectionContext?: UmbDefaultCollectionContext<UmbDocumentCollectionItemModel, UmbDocumentCollectionFilterModel>;
#collectionContext?: UmbDocumentCollectionContext;
constructor() {
super();

View File

@@ -87,7 +87,9 @@ export class UmbInputDocumentRootPickerElement extends FormControlMixin(UmbLitEl
});
#openDynamicRootOriginPicker() {
this.#openModal = this.#modalContext?.open(this, UMB_DYNAMIC_ROOT_ORIGIN_PICKER_MODAL, {});
this.#openModal = this.#modalContext?.open(this, UMB_DYNAMIC_ROOT_ORIGIN_PICKER_MODAL, {
data: { items: this._originManifests },
});
this.#openModal?.onSubmit().then((data: UmbTreePickerDynamicRoot) => {
const existingData = { ...this.data };
existingData.originKey = undefined;
@@ -98,7 +100,9 @@ export class UmbInputDocumentRootPickerElement extends FormControlMixin(UmbLitEl
}
#openDynamicRootQueryStepPicker() {
this.#openModal = this.#modalContext?.open(this, UMB_DYNAMIC_ROOT_QUERY_STEP_PICKER_MODAL, {});
this.#openModal = this.#modalContext?.open(this, UMB_DYNAMIC_ROOT_QUERY_STEP_PICKER_MODAL, {
data: { items: this._queryStepManifests },
});
this.#openModal?.onSubmit().then((step) => {
if (this.data) {
const querySteps = [...(this.data.querySteps ?? []), step];

View File

@@ -2,7 +2,7 @@ import type {
UmbCollectionBulkActionPermissions,
UmbCollectionConfiguration,
} from '../../../../../core/collection/types.js';
import { customElement, html, state } from '@umbraco-cms/backoffice/external/lit';
import { customElement, html, nothing, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbDataTypeDetailRepository } from '@umbraco-cms/backoffice/data-type';
import { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
@@ -58,7 +58,6 @@ export class UmbDocumentWorkspaceViewCollectionElement extends UmbLitElement imp
const config = new UmbPropertyEditorConfigCollection(dataType.values);
return {
unique: this._documentUnique,
dataTypeId: dataType.unique,
allowedEntityBulkActions: config?.getValueByAlias<UmbCollectionBulkActionPermissions>('bulkActionPermissions'),
orderBy: config?.getValueByAlias('orderBy') ?? 'updateDate',
orderDirection: config?.getValueByAlias('orderDirection') ?? 'asc',
@@ -69,7 +68,7 @@ export class UmbDocumentWorkspaceViewCollectionElement extends UmbLitElement imp
}
render() {
if (!this._config?.unique || !this._config?.dataTypeId) return html`<uui-loader></uui-loader>`;
if (!this._config?.unique) return nothing;
return html`<umb-collection alias="Umb.Collection.Document" .config=${this._config}></umb-collection>`;
}
}

View File

@@ -1,12 +1,12 @@
import { UmbDocumentPickerContext } from '../../documents/documents/components/input-document/input-document.context.js';
import type { UmbDynamicRootOriginModalData } from './index.js';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import { css, html, customElement, state, ifDefined, repeat } from '@umbraco-cms/backoffice/external/lit';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import type { ManifestDynamicRootOrigin } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbTreePickerDynamicRoot } from '@umbraco-cms/backoffice/components';
@customElement('umb-dynamic-root-origin-picker-modal')
export class UmbDynamicRootOriginPickerModalModalElement extends UmbModalBaseElement {
export class UmbDynamicRootOriginPickerModalModalElement extends UmbModalBaseElement<UmbDynamicRootOriginModalData> {
@state()
private _origins: Array<ManifestDynamicRootOrigin> = [];
@@ -16,10 +16,14 @@ export class UmbDynamicRootOriginPickerModalModalElement extends UmbModalBaseEle
super();
this.#documentPickerContext.max = 1;
}
this.observe(umbExtensionsRegistry.byType('dynamicRootOrigin'), (origins: Array<ManifestDynamicRootOrigin>) => {
this._origins = origins;
});
connectedCallback() {
super.connectedCallback();
if (this.data) {
this._origins = this.data.items;
}
}
#choose(item: ManifestDynamicRootOrigin) {

View File

@@ -1,28 +1,25 @@
import { UmbDocumentTypePickerContext } from '../../documents/document-types/components/input-document-type/input-document-type.context.js';
import type { UmbDynamicRootQueryStepModalData } from './index.js';
import { UmbId } from '@umbraco-cms/backoffice/id';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement, state, ifDefined, repeat } from '@umbraco-cms/backoffice/external/lit';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbTreePickerDynamicRootQueryStep } from '@umbraco-cms/backoffice/components';
import type { ManifestDynamicRootQueryStep } from '@umbraco-cms/backoffice/extension-registry';
@customElement('umb-dynamic-root-query-step-picker-modal')
export class UmbDynamicRootQueryStepPickerModalModalElement extends UmbModalBaseElement {
export class UmbDynamicRootQueryStepPickerModalModalElement extends UmbModalBaseElement<UmbDynamicRootQueryStepModalData> {
@state()
private _querySteps: Array<ManifestDynamicRootQueryStep> = [];
#documentTypePickerContext = new UmbDocumentTypePickerContext(this);
constructor() {
super();
connectedCallback() {
super.connectedCallback();
this.observe(
umbExtensionsRegistry.byType('dynamicRootQueryStep'),
(querySteps: Array<ManifestDynamicRootQueryStep>) => {
this._querySteps = querySteps;
},
);
if (this.data) {
this._querySteps = this.data.items;
}
}
#choose(item: ManifestDynamicRootQueryStep) {

View File

@@ -2,16 +2,31 @@ import {
UMB_DYNAMIC_ROOT_ORIGIN_PICKER_MODAL_ALIAS,
UMB_DYNAMIC_ROOT_QUERY_STEP_PICKER_MODAL_ALIAS,
} from './manifests.js';
import type {
ManifestDynamicRootOrigin,
ManifestDynamicRootQueryStep,
} from '@umbraco-cms/backoffice/extension-registry';
import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
export const UMB_DYNAMIC_ROOT_ORIGIN_PICKER_MODAL = new UmbModalToken(UMB_DYNAMIC_ROOT_ORIGIN_PICKER_MODAL_ALIAS, {
modal: {
type: 'sidebar',
size: 'small',
},
});
export interface UmbDynamicRootOriginModalData {
items: Array<ManifestDynamicRootOrigin>;
}
export const UMB_DYNAMIC_ROOT_QUERY_STEP_PICKER_MODAL = new UmbModalToken(
export interface UmbDynamicRootQueryStepModalData {
items: Array<ManifestDynamicRootQueryStep>;
}
export const UMB_DYNAMIC_ROOT_ORIGIN_PICKER_MODAL = new UmbModalToken<UmbDynamicRootOriginModalData>(
UMB_DYNAMIC_ROOT_ORIGIN_PICKER_MODAL_ALIAS,
{
modal: {
type: 'sidebar',
size: 'small',
},
},
);
export const UMB_DYNAMIC_ROOT_QUERY_STEP_PICKER_MODAL = new UmbModalToken<UmbDynamicRootQueryStepModalData>(
UMB_DYNAMIC_ROOT_QUERY_STEP_PICKER_MODAL_ALIAS,
{
modal: {

View File

@@ -12,13 +12,13 @@ const modals: Array<ManifestModal> = [
type: 'modal',
alias: UMB_DYNAMIC_ROOT_ORIGIN_PICKER_MODAL_ALIAS,
name: 'Choose an origin',
js: () => import('./dynamic-root-origin-picker-modal.element.js'),
element: () => import('./dynamic-root-origin-picker-modal.element.js'),
},
{
type: 'modal',
alias: UMB_DYNAMIC_ROOT_QUERY_STEP_PICKER_MODAL_ALIAS,
name: 'Append step to query',
js: () => import('./dynamic-root-query-step-picker-modal.element.js'),
element: () => import('./dynamic-root-query-step-picker-modal.element.js'),
},
];

View File

@@ -67,7 +67,7 @@ export class UmbLogViewerWorkspaceContext extends UmbControllerBase implements U
};
#savedSearches = new UmbObjectState<PagedSavedLogSearchResponseModel | undefined>(undefined);
savedSearches = this.#savedSearches.asObservablePart((data) => data?.items);
savedSearches = this.#savedSearches.asObservablePart((data) => data);
#logCount = new UmbObjectState<LogLevelCountsReponseModel | null>(null);
logCount = this.#logCount.asObservable();
@@ -168,8 +168,8 @@ export class UmbLogViewerWorkspaceContext extends UmbControllerBase implements U
return this.#dateRange.getValue();
}
async getSavedSearches() {
const { data } = await this.#repository.getSavedSearches({ skip: 0, take: 100 });
async getSavedSearches({ skip = 0, take = 999 }: { skip?: number; take?: number } = {}) {
const { data } = await this.#repository.getSavedSearches({ skip, take });
if (data) {
this.#savedSearches.setValue(data);
} else {

View File

@@ -33,7 +33,11 @@ export class UmbLogViewerWorkspaceElement extends UmbLitElement {
}
render() {
return html` <umb-workspace-editor headline="Log Viewer" .enforceNoFooter=${true}> </umb-workspace-editor> `;
return html`
<umb-workspace-editor
headline=${this.localize.term('treeHeaders_logViewer')}
.enforceNoFooter=${true}></umb-workspace-editor>
`;
}
static styles = [

View File

@@ -4,7 +4,6 @@ import { html, nothing, customElement, property, state } from '@umbraco-cms/back
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { LoggerResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
//TODO: implement the saved searches pagination when the API total bug is fixed
@customElement('umb-log-viewer-log-level-overview')
export class UmbLogViewerLogLevelOverviewElement extends UmbLitElement {
#logViewerContext?: UmbLogViewerWorkspaceContext;

View File

@@ -1,25 +1,31 @@
import type { UmbLogViewerWorkspaceContext } from '../../../logviewer.context.js';
import { UMB_APP_LOG_VIEWER_CONTEXT } from '../../../logviewer.context.js';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { css, html, customElement, state, nothing } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type {
PagedLogTemplateResponseModel,
LogTemplateResponseModel,
SavedLogSearchResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
import type { UUIPaginationEvent } from '@umbraco-cms/backoffice/external/uui';
//TODO: fix pagination bug when API is fixed
@customElement('umb-log-viewer-message-templates-overview')
export class UmbLogViewerMessageTemplatesOverviewElement extends UmbLitElement {
#itemsPerPage = 10;
#currentPage = 1;
@state()
private _messageTemplates: PagedLogTemplateResponseModel | null = null;
private _total = 0;
@state()
private _messageTemplates: Array<LogTemplateResponseModel> = [];
#logViewerContext?: UmbLogViewerWorkspaceContext;
constructor() {
super();
this.consumeContext(UMB_APP_LOG_VIEWER_CONTEXT, (instance) => {
this.#logViewerContext = instance;
this.#logViewerContext?.getMessageTemplates(0, 10);
this.#logViewerContext?.getMessageTemplates(0, this.#itemsPerPage);
this.#observeStuff();
});
}
@@ -27,13 +33,19 @@ export class UmbLogViewerMessageTemplatesOverviewElement extends UmbLitElement {
#observeStuff() {
if (!this.#logViewerContext) return;
this.observe(this.#logViewerContext.messageTemplates, (templates) => {
this._messageTemplates = templates ?? null;
this._messageTemplates = templates?.items ?? [];
this._total = templates?.total ?? 0;
});
}
#getMessageTemplates() {
const take = this._messageTemplates?.items?.length ?? 0;
this.#logViewerContext?.getMessageTemplates(0, take + 10);
const skip = this.#currentPage * this.#itemsPerPage - this.#itemsPerPage;
this.#logViewerContext?.getMessageTemplates(skip, this.#itemsPerPage);
}
#onChangePage(event: UUIPaginationEvent) {
this.#currentPage = event.target.current;
this.#getMessageTemplates();
}
#renderSearchItem = (searchListItem: SavedLogSearchResponseModel) => {
@@ -54,11 +66,11 @@ export class UmbLogViewerMessageTemplatesOverviewElement extends UmbLitElement {
render() {
return html`
<uui-box headline="Common Log Messages" id="saved-searches">
<p style="font-style: italic;">Total Unique Message types: ${this._messageTemplates?.total}</p>
<p style="font-style: italic;">Total Unique Message types: ${this._total}</p>
<uui-table>
${this._messageTemplates
? this._messageTemplates.items.map(
? this._messageTemplates.map(
(template) =>
html`<uui-table-row>
<uui-table-cell>
@@ -70,17 +82,15 @@ export class UmbLogViewerMessageTemplatesOverviewElement extends UmbLitElement {
</a>
</uui-table-cell>
</uui-table-row>`,
)
)
: ''}
</uui-table>
<uui-button
id="show-more-templates-btn"
look="primary"
@click=${this.#getMessageTemplates}
label="Show more templates">
Show more
</uui-button>
${this._total > this.#itemsPerPage
? html`<uui-pagination
.current=${this.#currentPage}
.total=${Math.ceil(this._total / this.#itemsPerPage)}
@change=${this.#onChangePage}></uui-pagination>`
: nothing}
</uui-box>
`;
}
@@ -88,6 +98,10 @@ export class UmbLogViewerMessageTemplatesOverviewElement extends UmbLitElement {
static styles = [
UmbTextStyles,
css`
uui-pagination {
margin-top: var(--uui-size-layout-1);
}
#show-more-templates-btn {
margin-top: var(--uui-size-space-5);
}

View File

@@ -1,23 +1,29 @@
import type { UmbLogViewerWorkspaceContext } from '../../../logviewer.context.js';
import { UMB_APP_LOG_VIEWER_CONTEXT } from '../../../logviewer.context.js';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { css, html, customElement, state, nothing } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { SavedLogSearchResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
import type { UUIPaginationEvent } from '@umbraco-cms/backoffice/external/uui';
//TODO: implement the saved searches pagination when the API total bug is fixed
@customElement('umb-log-viewer-saved-searches-overview')
export class UmbLogViewerSavedSearchesOverviewElement extends UmbLitElement {
#itemsPerPage = 999;
#currentPage = 1;
@state()
private _savedSearches: SavedLogSearchResponseModel[] = [];
@state()
private _total = 0;
#logViewerContext?: UmbLogViewerWorkspaceContext;
constructor() {
super();
this.consumeContext(UMB_APP_LOG_VIEWER_CONTEXT, (instance) => {
this.#logViewerContext = instance;
this.#logViewerContext?.getSavedSearches();
this.#logViewerContext?.getSavedSearches({ skip: 0, take: this.#itemsPerPage });
this.#observeStuff();
});
}
@@ -25,10 +31,21 @@ export class UmbLogViewerSavedSearchesOverviewElement extends UmbLitElement {
#observeStuff() {
if (!this.#logViewerContext) return;
this.observe(this.#logViewerContext.savedSearches, (savedSearches) => {
this._savedSearches = savedSearches ?? [];
this._savedSearches = savedSearches?.items ?? [];
this._total = savedSearches?.total ?? 0;
});
}
#getSavedSearches() {
const skip = this.#currentPage * this.#itemsPerPage - this.#itemsPerPage;
this.#logViewerContext?.getSavedSearches({ skip, take: this.#itemsPerPage });
}
#onChangePage(event: UUIPaginationEvent) {
this.#currentPage = event.target.current;
this.#getSavedSearches();
}
#renderSearchItem = (searchListItem: SavedLogSearchResponseModel) => {
return html` <li>
<uui-menu-item
@@ -47,6 +64,12 @@ export class UmbLogViewerSavedSearchesOverviewElement extends UmbLitElement {
<ul>
${this.#renderSearchItem({ name: 'All logs', query: '' })} ${this._savedSearches.map(this.#renderSearchItem)}
</ul>
${this._total > this.#itemsPerPage
? html`<uui-pagination
.current=${this.#currentPage}
.total=${Math.ceil(this._total / this.#itemsPerPage)}
@change=${this.#onChangePage}></uui-pagination>`
: nothing}
</uui-box>`;
}

View File

@@ -89,12 +89,12 @@ export class UmbLogViewerMessagesListElement extends UmbLitElement {
.properties=${log.properties ?? []}
.exception=${log.exception ?? ''}
.messageTemplate=${log.messageTemplate ?? ''}></umb-log-viewer-message>`,
)}`
)}`
: html`
<span id="empty">
<uui-icon name="icon-search"></uui-icon>Sorry, we cannot find what you are looking for.
</span>
`}`;
`}`;
}
render() {
@@ -124,6 +124,10 @@ export class UmbLogViewerMessagesListElement extends UmbLitElement {
static styles = [
css`
uui-pagination {
display: block;
margin-bottom: var(--uui-size-layout-1);
}
uui-box {
--uui-box-default-padding: 0;
}

View File

@@ -71,7 +71,7 @@ export class UmbLogViewerSearchInputElement extends UmbLitElement {
#observeStuff() {
if (!this.#logViewerContext) return;
this.observe(this.#logViewerContext.savedSearches, (savedSearches) => {
this._savedSearches = savedSearches ?? [];
this._savedSearches = savedSearches?.items ?? [];
this._isQuerySaved = this._savedSearches.some((search) => search.query === this._inputQuery);
});
@@ -156,13 +156,13 @@ export class UmbLogViewerSearchInputElement extends UmbLitElement {
${this._showLoader
? html`<div id="loader-container" slot="append">
<uui-loader-circle></uui-loader-circle>
</div>`
</div>`
: ''}
${this._inputQuery
? html`${!this._isQuerySaved
? html`<uui-button compact slot="append" label="Save search" @click=${this.#openSaveSearchDialog}
><uui-icon name="icon-favorite"></uui-icon
></uui-button>`
></uui-button>`
: ''}<uui-button compact slot="append" label="Clear" @click=${this.#clearQuery}
><uui-icon name="icon-delete"></uui-icon
></uui-button>`

View File

@@ -57,6 +57,10 @@ export class UmbLogViewerSearchViewElement extends UmbLitElement {
static styles = [
UmbTextStyles,
css`
:host {
margin-bottom: var(--uui-size-space-2);
}
uui-box {
--uui-box-default-padding: 0;
}

View File

@@ -42,7 +42,7 @@ export class UmbMediaTypeServerDataSource implements UmbDetailDataSource<UmbMedi
name: '',
alias: '',
description: '',
icon: '',
icon: 'icon-picture',
allowedAtRoot: false,
variesByCulture: false,
variesBySegment: false,

View File

@@ -209,8 +209,7 @@ export class UmbMediaTypeWorkspaceViewEditTabElement extends UmbLitElement {
label=${this.localize.term('contentTypeEditor_addGroup')}
id="add"
look="placeholder"
@click=${this.#onAddGroup}>
</uui-button>`
@click=${this.#onAddGroup}></uui-button>`
: ''}
`;
}

View File

@@ -9,7 +9,5 @@ export class UmbMediaCollectionContext extends UmbDefaultCollectionContext<
> {
constructor(host: UmbControllerHost) {
super(host, UMB_MEDIA_GRID_COLLECTION_VIEW_ALIAS);
this.selection.setSelectable(true);
}
}

View File

@@ -1,12 +1,15 @@
import type { UmbMediaCollectionFilterModel } from '../types.js';
import { UmbMediaCollectionServerDataSource } from './media-collection.server.data-source.js';
import { UmbRepositoryBase } from '@umbraco-cms/backoffice/repository';
import type { UmbCollectionRepository } from '@umbraco-cms/backoffice/collection';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
export class UmbMediaCollectionRepository implements UmbCollectionRepository {
export class UmbMediaCollectionRepository extends UmbRepositoryBase implements UmbCollectionRepository {
#collectionSource: UmbMediaCollectionServerDataSource;
constructor(host: UmbControllerHost) {
super(host);
this.#collectionSource = new UmbMediaCollectionServerDataSource(host);
}

View File

@@ -1,14 +1,17 @@
import type { UmbImageCropperPropertyEditorValue } from './types.js';
import type { UmbInputImageCropperFieldElement } from './image-cropper-field.element.js';
import { html, customElement, property, query, state } from '@umbraco-cms/backoffice/external/lit';
import './image-cropper.element.js';
import './image-cropper-focus-setter.element.js';
import './image-cropper-preview.element.js';
import './image-cropper-field.element.js';
import type { UUIFileDropzoneElement, UUIFileDropzoneEvent } from '@umbraco-cms/backoffice/external/uui';
import { UmbId } from '@umbraco-cms/backoffice/id';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { type TemporaryFileQueueItem, UmbTemporaryFileManager } from '@umbraco-cms/backoffice/temporary-file';
import { UmbTemporaryFileManager } from '@umbraco-cms/backoffice/temporary-file';
import { assignToFrozenObject } from '@umbraco-cms/backoffice/observable-api';
import './image-cropper.element.js';
import './image-cropper-focus-setter.element.js';
import './image-cropper-preview.element.js';
import './image-cropper-field.element.js';
@customElement('umb-input-image-cropper')
export class UmbInputImageCropperElement extends UmbLitElement {
@@ -22,6 +25,9 @@ export class UmbInputImageCropperElement extends UmbLitElement {
focalPoint: { left: 0.5, top: 0.5 },
};
@property({ attribute: false })
crops: UmbImageCropperPropertyEditorValue['crops'] = [];
@state()
file?: File;
@@ -33,18 +39,11 @@ export class UmbInputImageCropperElement extends UmbLitElement {
constructor() {
super();
this.#manager = new UmbTemporaryFileManager(this);
// this.observe(this.#manager.isReady, (value) => (this.error = !value));
this.observe(this.#manager.queue, this.#onQueueUpdate);
}
#onQueueUpdate = (value: TemporaryFileQueueItem[]) => {
if (value.length) {
// this.file = value[0].file;
// this.fileUnique = value[0].unique;
// this.value.src = value[0].unique;
}
};
protected firstUpdated(): void {
this.#mergeCrops();
}
#onUpload(e: UUIFileDropzoneEvent) {
const file = e.detail.files[0];
@@ -53,7 +52,8 @@ export class UmbInputImageCropperElement extends UmbLitElement {
this.file = file;
this.fileUnique = unique;
this.value.src = unique;
this.value = assignToFrozenObject(this.value, { src: unique });
this.#manager?.uploadOne(unique, file, 'waiting');
@@ -66,7 +66,7 @@ export class UmbInputImageCropperElement extends UmbLitElement {
}
#onRemove = () => {
this.value = { ...this.value, src: '' };
this.value = assignToFrozenObject(this.value, { src: '' });
if (!this.fileUnique) return;
this.#manager?.removeOne(this.fileUnique);
this.fileUnique = undefined;
@@ -75,6 +75,24 @@ export class UmbInputImageCropperElement extends UmbLitElement {
this.dispatchEvent(new UmbChangeEvent());
};
#mergeCrops() {
// Replace crops from the value with the crops from the config while keeping the coordinates from the value if they exist.
const filteredCrops = this.crops.map((crop) => {
const cropFromValue = this.value.crops.find((valueCrop) => valueCrop.alias === crop.alias);
const result = {
...crop,
coordinates: cropFromValue?.coordinates ?? undefined,
};
return result;
});
this.value = {
...this.value,
crops: filteredCrops,
};
}
render() {
if (this.value.src || this.file) {
return this.#renderImageCropper();
@@ -91,9 +109,16 @@ export class UmbInputImageCropperElement extends UmbLitElement {
`;
}
#onChange(e: any) {
this.value = e.target.value;
#onChange(e: CustomEvent) {
const value = (e.target as UmbInputImageCropperFieldElement).value;
if (!value) {
this.value = { src: '', crops: [], focalPoint: { left: 0.5, top: 0.5 } };
this.dispatchEvent(new UmbChangeEvent());
return;
}
this.value = value;
this.dispatchEvent(new UmbChangeEvent());
}

View File

@@ -1,4 +1,5 @@
import type { UmbMediaItemModel } from '../../repository/item/types.js';
import { UMB_MEDIA_ITEM_REPOSITORY_ALIAS } from '../../repository/index.js';
import { UmbPickerInputContext } from '@umbraco-cms/backoffice/picker-input';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UMB_MEDIA_TREE_PICKER_MODAL } from '@umbraco-cms/backoffice/modal';
@@ -7,6 +8,6 @@ export class UmbMediaPickerContext extends UmbPickerInputContext<UmbMediaItemMod
constructor(host: UmbControllerHost) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
super(host, 'Umb.Repository.Media', UMB_MEDIA_TREE_PICKER_MODAL);
super(host, UMB_MEDIA_ITEM_REPOSITORY_ALIAS, UMB_MEDIA_TREE_PICKER_MODAL);
}
}

View File

@@ -3,9 +3,9 @@ import { UmbMediaPickerContext } from './input-media.context.js';
import { css, html, customElement, property, state, ifDefined, repeat } from '@umbraco-cms/backoffice/external/lit';
import { FormControlMixin } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal';
import { type UmbSorterConfig, UmbSorterController } from '@umbraco-cms/backoffice/sorter';
import { splitStringToArray } from '@umbraco-cms/backoffice/utils';
const SORTER_CONFIG: UmbSorterConfig<string> = {
getUniqueOfElement: (element) => {

View File

@@ -1,8 +1,12 @@
import type { UmbImageCropperPropertyEditorValue } from '../../components/index.js';
import { html, customElement, property, nothing } from '@umbraco-cms/backoffice/external/lit';
import type { UmbImageCropperPropertyEditorValue, UmbInputImageCropperElement } from '../../components/index.js';
import { html, customElement, property, nothing, state } from '@umbraco-cms/backoffice/external/lit';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import '../../components/input-image-cropper/input-image-cropper.element.js';
import {
UmbPropertyValueChangeEvent,
type UmbPropertyEditorConfigCollection,
} from '@umbraco-cms/backoffice/property-editor';
/**
* @element umb-property-editor-ui-image-cropper
@@ -16,6 +20,9 @@ export class UmbPropertyEditorUIImageCropperElement extends UmbLitElement implem
focalPoint: { left: 0.5, top: 0.5 },
};
@state()
crops: UmbImageCropperPropertyEditorValue['crops'] = [];
updated(changedProperties: Map<string | number | symbol, unknown>) {
super.updated(changedProperties);
if (changedProperties.has('value')) {
@@ -29,31 +36,23 @@ export class UmbPropertyEditorUIImageCropperElement extends UmbLitElement implem
}
}
// #crops = [];
// @property({ attribute: false })
// public set config(config: UmbPropertyEditorConfigCollection | undefined) {
// this.#crops = config?.getValueByAlias('crops') ?? [];
// if (!this.value) {
// //TODO: How should we combine the crops from the value with the configuration?
// this.value = {
// crops: this.#crops,
// focalPoint: { left: 0.5, top: 0.5 },
// src: 'https://picsum.photos/seed/picsum/1920/1080',
// };
// }
// }
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this.crops = config?.getValueByAlias<UmbImageCropperPropertyEditorValue['crops']>('crops') ?? [];
}
#onChange(e: Event) {
this.value = (e.target as any).value;
this.dispatchEvent(new CustomEvent('property-value-change'));
this.value = (e.target as UmbInputImageCropperElement).value;
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
render() {
if (!this.value) return nothing;
return html`<umb-input-image-cropper @change=${this.#onChange} .value=${this.value}></umb-input-image-cropper>`;
return html`<umb-input-image-cropper
@change=${this.#onChange}
.value=${this.value}
.crops=${this.crops}></umb-input-image-cropper>`;
}
}

View File

@@ -1 +1,9 @@
export * from './property-editor-ui-media-picker.element.js';
export type UmbMediaPickerPropertyValue = {
key: string;
mediaKey: string;
mediaTypeAlias: string;
focalPoint: { left: number; top: number } | null;
crops: Array<{ alias: string; width: number; height: number }>;
};

View File

@@ -1,5 +1,6 @@
import type { UmbInputMediaElement } from '../../components/input-media/input-media.element.js';
import '../../components/input-media/input-media.element.js';
import type { UmbMediaPickerPropertyValue } from './index.js';
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import {
UmbPropertyValueChangeEvent,
@@ -7,14 +8,23 @@ import {
} from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbId } from '@umbraco-cms/backoffice/id';
/**
* @element umb-property-editor-ui-media-picker
*/
@customElement('umb-property-editor-ui-media-picker')
export class UmbPropertyEditorUIMediaPickerElement extends UmbLitElement implements UmbPropertyEditorUiElement {
@property()
public value?: string;
@property({ attribute: false })
public set value(value: Array<UmbMediaPickerPropertyValue>) {
this.#value = value;
this._items = this.value ? this.value.map((x) => x.mediaKey) : [];
}
//TODO: Add support for document specific crops. The server side already supports this.
public get value() {
return this.#value;
}
@property({ attribute: false })
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
@@ -30,21 +40,39 @@ export class UmbPropertyEditorUIMediaPickerElement extends UmbLitElement impleme
return undefined;
}
@state()
_items: Array<string> = [];
@state()
private _limitMin: number = 0;
@state()
private _limitMax: number = Infinity;
private _onChange(event: CustomEvent) {
this.value = (event.target as UmbInputMediaElement).selectedIds.join(',');
#value: Array<UmbMediaPickerPropertyValue> = [];
#onChange(event: CustomEvent) {
const selectedIds = (event.target as UmbInputMediaElement).selectedIds;
const result = selectedIds.map((mediaKey) => {
return {
key: UmbId.new(),
mediaKey,
mediaTypeAlias: '',
focalPoint: null,
crops: [],
};
});
this.value = result;
this._items = this.value ? this.value.map((x) => x.mediaKey) : [];
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
render() {
return html`
<umb-input-media
@change=${this._onChange}
.value=${this.value ?? ''}
@change=${this.#onChange}
.selectedIds=${this._items}
.min=${this._limitMin}
.max=${this._limitMax}>
<umb-localize key="general_add">Add</umb-localize>

View File

@@ -1,4 +1,4 @@
import { customElement, html, state } from '@umbraco-cms/backoffice/external/lit';
import { customElement, html, nothing, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbDataTypeDetailRepository } from '@umbraco-cms/backoffice/data-type';
import { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
@@ -58,7 +58,6 @@ export class UmbMediaWorkspaceViewCollectionElement extends UmbLitElement implem
const config = new UmbPropertyEditorConfigCollection(dataType.values);
return {
unique: this._mediaUnique,
dataTypeId: dataType.unique,
allowedEntityBulkActions: config?.getValueByAlias<UmbCollectionBulkActionPermissions>('bulkActionPermissions'),
orderBy: config?.getValueByAlias('orderBy') ?? 'updateDate',
orderDirection: config?.getValueByAlias('orderDirection') ?? 'asc',
@@ -69,7 +68,7 @@ export class UmbMediaWorkspaceViewCollectionElement extends UmbLitElement implem
}
render() {
if (!this._config?.unique || !this._config?.dataTypeId) return html`<uui-loader></uui-loader>`;
if (!this._config?.unique) return nothing;
return html`<umb-collection .alias=${UMB_MEDIA_COLLECTION_ALIAS} .config=${this._config}></umb-collection>`;
}
}

View File

@@ -78,7 +78,7 @@ export class UmbRelationTypeServerDataSource {
isBidirectional: false,
isDependency: false,
path: '',
isSystemRelationType: false,
isDeletable: false,
};
return { data };