Merge branch 'main' into bugfix/rename-file-system-file

This commit is contained in:
Mads Rasmussen
2024-03-30 19:05:18 +01:00
193 changed files with 2415 additions and 2889 deletions

View File

@@ -10141,9 +10141,9 @@
"dev": true
},
"node_modules/cookie": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
"dev": true,
"engines": {
"node": ">= 0.6"
@@ -11760,9 +11760,9 @@
}
},
"node_modules/express": {
"version": "4.18.3",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz",
"integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==",
"version": "4.19.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
"dev": true,
"dependencies": {
"accepts": "~1.3.8",
@@ -11770,7 +11770,7 @@
"body-parser": "1.20.2",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.5.0",
"cookie": "0.6.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",

View File

@@ -69,7 +69,6 @@ export type { CreateMemberTypeRequestModel } from './models/CreateMemberTypeRequ
export type { CreatePackageRequestModel } from './models/CreatePackageRequestModel';
export type { CreatePartialViewFolderRequestModel } from './models/CreatePartialViewFolderRequestModel';
export type { CreatePartialViewRequestModel } from './models/CreatePartialViewRequestModel';
export type { CreateRelationTypeRequestModel } from './models/CreateRelationTypeRequestModel';
export type { CreateScriptFolderRequestModel } from './models/CreateScriptFolderRequestModel';
export type { CreateScriptRequestModel } from './models/CreateScriptRequestModel';
export type { CreateStylesheetFolderRequestModel } from './models/CreateStylesheetFolderRequestModel';
@@ -94,6 +93,7 @@ export type { DataTypePropertyReferenceModel } from './models/DataTypePropertyRe
export type { DataTypeReferenceResponseModel } from './models/DataTypeReferenceResponseModel';
export type { DataTypeResponseModel } from './models/DataTypeResponseModel';
export type { DataTypeTreeItemResponseModel } from './models/DataTypeTreeItemResponseModel';
export type { DefaultReferenceResponseModel } from './models/DefaultReferenceResponseModel';
export type { DeleteUserGroupsRequestModel } from './models/DeleteUserGroupsRequestModel';
export type { DeleteUsersRequestModel } from './models/DeleteUsersRequestModel';
export type { DictionaryItemItemResponseModel } from './models/DictionaryItemItemResponseModel';
@@ -111,6 +111,7 @@ export type { DocumentItemResponseModel } from './models/DocumentItemResponseMod
export type { DocumentNotificationResponseModel } from './models/DocumentNotificationResponseModel';
export type { DocumentPermissionPresentationModel } from './models/DocumentPermissionPresentationModel';
export type { DocumentRecycleBinItemResponseModel } from './models/DocumentRecycleBinItemResponseModel';
export type { DocumentReferenceResponseModel } from './models/DocumentReferenceResponseModel';
export type { DocumentResponseModel } from './models/DocumentResponseModel';
export type { DocumentTreeItemResponseModel } from './models/DocumentTreeItemResponseModel';
export type { DocumentTypeCleanupModel } from './models/DocumentTypeCleanupModel';
@@ -193,6 +194,7 @@ export type { MediaCollectionResponseModel } from './models/MediaCollectionRespo
export type { MediaConfigurationResponseModel } from './models/MediaConfigurationResponseModel';
export type { MediaItemResponseModel } from './models/MediaItemResponseModel';
export type { MediaRecycleBinItemResponseModel } from './models/MediaRecycleBinItemResponseModel';
export type { MediaReferenceResponseModel } from './models/MediaReferenceResponseModel';
export type { MediaResponseModel } from './models/MediaResponseModel';
export type { MediaTreeItemResponseModel } from './models/MediaTreeItemResponseModel';
export type { MediaTypeCollectionReferenceResponseModel } from './models/MediaTypeCollectionReferenceResponseModel';
@@ -221,7 +223,9 @@ export type { MemberTypeCompositionRequestModel } from './models/MemberTypeCompo
export type { MemberTypeCompositionResponseModel } from './models/MemberTypeCompositionResponseModel';
export type { MemberTypeItemResponseModel } from './models/MemberTypeItemResponseModel';
export type { MemberTypePropertyTypeContainerResponseModel } from './models/MemberTypePropertyTypeContainerResponseModel';
export type { MemberTypePropertyTypeModelBaseModel } from './models/MemberTypePropertyTypeModelBaseModel';
export type { MemberTypePropertyTypeResponseModel } from './models/MemberTypePropertyTypeResponseModel';
export type { MemberTypePropertyTypeVisibilityModel } from './models/MemberTypePropertyTypeVisibilityModel';
export type { MemberTypeReferenceResponseModel } from './models/MemberTypeReferenceResponseModel';
export type { MemberTypeResponseModel } from './models/MemberTypeResponseModel';
export type { MemberValueModel } from './models/MemberValueModel';
@@ -266,6 +270,7 @@ export type { PagedFileSystemTreeItemPresentationModel } from './models/PagedFil
export type { PagedHealthCheckGroupResponseModel } from './models/PagedHealthCheckGroupResponseModel';
export type { PagedHelpPageResponseModel } from './models/PagedHelpPageResponseModel';
export type { PagedIndexResponseModel } from './models/PagedIndexResponseModel';
export type { PagedIReferenceResponseModel } from './models/PagedIReferenceResponseModel';
export type { PagedLanguageResponseModel } from './models/PagedLanguageResponseModel';
export type { PagedLoggerResponseModel } from './models/PagedLoggerResponseModel';
export type { PagedLogMessageResponseModel } from './models/PagedLogMessageResponseModel';
@@ -283,9 +288,9 @@ export type { PagedPackageMigrationStatusResponseModel } from './models/PagedPac
export type { PagedPartialViewSnippetItemResponseModel } from './models/PagedPartialViewSnippetItemResponseModel';
export type { PagedProblemDetailsModel } from './models/PagedProblemDetailsModel';
export type { PagedRedirectUrlResponseModel } from './models/PagedRedirectUrlResponseModel';
export type { PagedRelationItemResponseModel } from './models/PagedRelationItemResponseModel';
export type { PagedReferenceByIdModel } from './models/PagedReferenceByIdModel';
export type { PagedRelationResponseModel } from './models/PagedRelationResponseModel';
export type { PagedRelationTypeTreeItemResponseModel } from './models/PagedRelationTypeTreeItemResponseModel';
export type { PagedRelationTypeResponseModel } from './models/PagedRelationTypeResponseModel';
export type { PagedSavedLogSearchResponseModel } from './models/PagedSavedLogSearchResponseModel';
export type { PagedSearcherResponseModel } from './models/PagedSearcherResponseModel';
export type { PagedSearchResultResponseModel } from './models/PagedSearchResultResponseModel';
@@ -318,7 +323,7 @@ export { RedirectStatusModel } from './models/RedirectStatusModel';
export type { RedirectUrlResponseModel } from './models/RedirectUrlResponseModel';
export type { RedirectUrlStatusResponseModel } from './models/RedirectUrlStatusResponseModel';
export type { ReferenceByIdModel } from './models/ReferenceByIdModel';
export type { RelationItemResponseModel } from './models/RelationItemResponseModel';
export type { RelationReferenceModel } from './models/RelationReferenceModel';
export type { RelationResponseModel } from './models/RelationResponseModel';
export type { RelationTypeBaseModel } from './models/RelationTypeBaseModel';
export type { RelationTypeItemResponseModel } from './models/RelationTypeItemResponseModel';
@@ -378,6 +383,9 @@ export type { TemplateResponseModel } from './models/TemplateResponseModel';
export type { TemporaryFileConfigurationResponseModel } from './models/TemporaryFileConfigurationResponseModel';
export type { TemporaryFileResponseModel } from './models/TemporaryFileResponseModel';
export type { TourStatusModel } from './models/TourStatusModel';
export type { TrackedReferenceContentTypeModel } from './models/TrackedReferenceContentTypeModel';
export type { TrackedReferenceDocumentTypeModel } from './models/TrackedReferenceDocumentTypeModel';
export type { TrackedReferenceMediaTypeModel } from './models/TrackedReferenceMediaTypeModel';
export type { TreeItemPresentationModel } from './models/TreeItemPresentationModel';
export type { UnknownTypePermissionPresentationModel } from './models/UnknownTypePermissionPresentationModel';
export type { UnlockUsersRequestModel } from './models/UnlockUsersRequestModel';
@@ -409,7 +417,6 @@ export type { UpdateMemberTypePropertyTypeRequestModel } from './models/UpdateMe
export type { UpdateMemberTypeRequestModel } from './models/UpdateMemberTypeRequestModel';
export type { UpdatePackageRequestModel } from './models/UpdatePackageRequestModel';
export type { UpdatePartialViewRequestModel } from './models/UpdatePartialViewRequestModel';
export type { UpdateRelationTypeRequestModel } from './models/UpdateRelationTypeRequestModel';
export type { UpdateScriptRequestModel } from './models/UpdateScriptRequestModel';
export type { UpdateStylesheetRequestModel } from './models/UpdateStylesheetRequestModel';
export type { UpdateTemplateRequestModel } from './models/UpdateTemplateRequestModel';
@@ -486,7 +493,6 @@ export { TelemetryResource } from './services/TelemetryResource';
export { TemplateResource } from './services/TemplateResource';
export { TemporaryFileResource } from './services/TemporaryFileResource';
export { TourResource } from './services/TourResource';
export { TrackedReferenceResource } from './services/TrackedReferenceResource';
export { UpgradeResource } from './services/UpgradeResource';
export { UserResource } from './services/UserResource';
export { UserGroupResource } from './services/UserGroupResource';

View File

@@ -3,7 +3,7 @@
/* tslint:disable */
/* eslint-disable */
import type { PropertyTypeModelBaseModel } from './PropertyTypeModelBaseModel';
import type { MemberTypePropertyTypeModelBaseModel } from './MemberTypePropertyTypeModelBaseModel';
export type CreateMemberTypePropertyTypeRequestModel = PropertyTypeModelBaseModel;
export type CreateMemberTypePropertyTypeRequestModel = MemberTypePropertyTypeModelBaseModel;

View File

@@ -1,11 +0,0 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { RelationTypeBaseModel } from './RelationTypeBaseModel';
export type CreateRelationTypeRequestModel = (RelationTypeBaseModel & {
id?: string | null;
});

View File

@@ -17,6 +17,7 @@ export type CurrentUserResponseModel = {
avatarUrls: Array<string>;
languages: Array<string>;
hasAccessToAllLanguages: boolean;
hasAccessToSensitiveData: boolean;
fallbackPermissions: Array<string>;
permissions: Array<(DocumentPermissionPresentationModel | UnknownTypePermissionPresentationModel)>;
allowedSections: Array<string>;

View File

@@ -0,0 +1,12 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type DefaultReferenceResponseModel = {
id: string;
name?: string | null;
type?: string | null;
icon?: string | null;
};

View File

@@ -0,0 +1,14 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { TrackedReferenceDocumentTypeModel } from './TrackedReferenceDocumentTypeModel';
export type DocumentReferenceResponseModel = {
id: string;
name?: string | null;
published?: boolean | null;
documentType: TrackedReferenceDocumentTypeModel;
};

View File

@@ -0,0 +1,13 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { TrackedReferenceMediaTypeModel } from './TrackedReferenceMediaTypeModel';
export type MediaReferenceResponseModel = {
id: string;
name?: string | null;
mediaType: TrackedReferenceMediaTypeModel;
};

View File

@@ -0,0 +1,26 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { MemberTypePropertyTypeVisibilityModel } from './MemberTypePropertyTypeVisibilityModel';
import type { PropertyTypeAppearanceModel } from './PropertyTypeAppearanceModel';
import type { PropertyTypeValidationModel } from './PropertyTypeValidationModel';
import type { ReferenceByIdModel } from './ReferenceByIdModel';
export type MemberTypePropertyTypeModelBaseModel = {
id: string;
container?: ReferenceByIdModel | null;
sortOrder: number;
alias: string;
name: string;
description?: string | null;
dataType: ReferenceByIdModel;
variesByCulture: boolean;
variesBySegment: boolean;
validation: PropertyTypeValidationModel;
appearance: PropertyTypeAppearanceModel;
isSensitive: boolean;
visibility: MemberTypePropertyTypeVisibilityModel;
};

View File

@@ -3,7 +3,7 @@
/* tslint:disable */
/* eslint-disable */
import type { PropertyTypeModelBaseModel } from './PropertyTypeModelBaseModel';
import type { MemberTypePropertyTypeModelBaseModel } from './MemberTypePropertyTypeModelBaseModel';
export type MemberTypePropertyTypeResponseModel = PropertyTypeModelBaseModel;
export type MemberTypePropertyTypeResponseModel = MemberTypePropertyTypeModelBaseModel;

View File

@@ -0,0 +1,10 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type MemberTypePropertyTypeVisibilityModel = {
memberCanView: boolean;
memberCanEdit: boolean;
};

View File

@@ -0,0 +1,14 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { DefaultReferenceResponseModel } from './DefaultReferenceResponseModel';
import type { DocumentReferenceResponseModel } from './DocumentReferenceResponseModel';
import type { MediaReferenceResponseModel } from './MediaReferenceResponseModel';
export type PagedIReferenceResponseModel = {
total: number;
items: Array<(DefaultReferenceResponseModel | DocumentReferenceResponseModel | MediaReferenceResponseModel)>;
};

View File

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

View File

@@ -3,10 +3,10 @@
/* tslint:disable */
/* eslint-disable */
import type { RelationItemResponseModel } from './RelationItemResponseModel';
import type { RelationTypeResponseModel } from './RelationTypeResponseModel';
export type PagedRelationItemResponseModel = {
export type PagedRelationTypeResponseModel = {
total: number;
items: Array<RelationItemResponseModel>;
items: Array<RelationTypeResponseModel>;
};

View File

@@ -1,12 +0,0 @@
/* 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

@@ -1,18 +0,0 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type RelationItemResponseModel = {
nodeId: string;
nodeName?: string | null;
nodeType?: string | null;
nodePublished?: boolean | null;
contentTypeIcon?: string | null;
contentTypeAlias?: string | null;
contentTypeName?: string | null;
relationTypeName?: string | null;
relationTypeIsBidirectional: boolean;
relationTypeIsDependency: boolean;
};

View File

@@ -0,0 +1,10 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type RelationReferenceModel = {
id: string;
name?: string | null;
};

View File

@@ -3,11 +3,14 @@
/* tslint:disable */
/* eslint-disable */
import type { ReferenceByIdModel } from './ReferenceByIdModel';
import type { RelationReferenceModel } from './RelationReferenceModel';
export type RelationResponseModel = {
parentId: string;
parentName?: string | null;
childId: string;
childName?: string | null;
id: string;
relationType: ReferenceByIdModel;
parent: RelationReferenceModel;
child: RelationReferenceModel;
createDate: string;
comment?: string | null;
};

View File

@@ -6,8 +6,6 @@
export type RelationTypeBaseModel = {
name: string;
isBidirectional: boolean;
parentObjectType?: string | null;
childObjectType?: string | null;
isDependency: boolean;
};

View File

@@ -3,14 +3,13 @@
/* tslint:disable */
/* eslint-disable */
import type { ObjectTypeResponseModel } from './ObjectTypeResponseModel';
import type { RelationTypeBaseModel } from './RelationTypeBaseModel';
export type RelationTypeResponseModel = (RelationTypeBaseModel & {
id: string;
alias?: string | null;
path: string;
isDeletable: boolean;
parentObjectTypeName?: string | null;
childObjectTypeName?: string | null;
parentObject?: ObjectTypeResponseModel | null;
childObject?: ObjectTypeResponseModel | null;
});

View File

@@ -0,0 +1,11 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type TrackedReferenceContentTypeModel = {
icon?: string | null;
alias?: string | null;
name?: string | null;
};

View File

@@ -0,0 +1,9 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { TrackedReferenceContentTypeModel } from './TrackedReferenceContentTypeModel';
export type TrackedReferenceDocumentTypeModel = TrackedReferenceContentTypeModel;

View File

@@ -0,0 +1,9 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { TrackedReferenceContentTypeModel } from './TrackedReferenceContentTypeModel';
export type TrackedReferenceMediaTypeModel = TrackedReferenceContentTypeModel;

View File

@@ -3,7 +3,7 @@
/* tslint:disable */
/* eslint-disable */
import type { PropertyTypeModelBaseModel } from './PropertyTypeModelBaseModel';
import type { MemberTypePropertyTypeModelBaseModel } from './MemberTypePropertyTypeModelBaseModel';
export type UpdateMemberTypePropertyTypeRequestModel = PropertyTypeModelBaseModel;
export type UpdateMemberTypePropertyTypeRequestModel = MemberTypePropertyTypeModelBaseModel;

View File

@@ -1,9 +0,0 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { RelationTypeBaseModel } from './RelationTypeBaseModel';
export type UpdateRelationTypeRequestModel = RelationTypeBaseModel;

View File

@@ -16,6 +16,8 @@ import type { MoveMediaRequestModel } from '../models/MoveMediaRequestModel';
import type { PagedDocumentCollectionResponseModel } from '../models/PagedDocumentCollectionResponseModel';
import type { PagedDocumentRecycleBinItemResponseModel } from '../models/PagedDocumentRecycleBinItemResponseModel';
import type { PagedDocumentTreeItemResponseModel } from '../models/PagedDocumentTreeItemResponseModel';
import type { PagedIReferenceResponseModel } from '../models/PagedIReferenceResponseModel';
import type { PagedReferenceByIdModel } from '../models/PagedReferenceByIdModel';
import type { PublicAccessRequestModel } from '../models/PublicAccessRequestModel';
import type { PublishDocumentRequestModel } from '../models/PublishDocumentRequestModel';
import type { PublishDocumentWithDescendantsRequestModel } from '../models/PublishDocumentWithDescendantsRequestModel';
@@ -521,6 +523,64 @@ export class DocumentResource {
});
}
/**
* @returns PagedIReferenceResponseModel Success
* @throws ApiError
*/
public static getDocumentByIdReferencedBy({
id,
skip,
take = 20,
}: {
id: string,
skip?: number,
take?: number,
}): CancelablePromise<PagedIReferenceResponseModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/document/{id}/referenced-by',
path: {
'id': id,
},
query: {
'skip': skip,
'take': take,
},
errors: {
401: `The resource is protected and requires an authentication token`,
},
});
}
/**
* @returns PagedReferenceByIdModel Success
* @throws ApiError
*/
public static getDocumentByIdReferencedDescendants({
id,
skip,
take = 20,
}: {
id: string,
skip?: number,
take?: number,
}): CancelablePromise<PagedReferenceByIdModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/document/{id}/referenced-descendants',
path: {
'id': id,
},
query: {
'skip': skip,
'take': take,
},
errors: {
401: `The resource is protected and requires an authentication token`,
},
});
}
/**
* @returns string Success
* @throws ApiError
@@ -579,6 +639,33 @@ export class DocumentResource {
});
}
/**
* @returns PagedReferenceByIdModel Success
* @throws ApiError
*/
public static getDocumentAreReferenced({
id,
skip,
take = 20,
}: {
id?: Array<string>,
skip?: number,
take?: number,
}): CancelablePromise<PagedReferenceByIdModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/document/are-referenced',
query: {
'id': id,
'skip': skip,
'take': take,
},
errors: {
401: `The resource is protected and requires an authentication token`,
},
});
}
/**
* @returns any Success
* @throws ApiError

View File

@@ -9,9 +9,11 @@ import type { MediaItemResponseModel } from '../models/MediaItemResponseModel';
import type { MediaResponseModel } from '../models/MediaResponseModel';
import type { MediaTreeItemResponseModel } from '../models/MediaTreeItemResponseModel';
import type { MoveMediaRequestModel } from '../models/MoveMediaRequestModel';
import type { PagedIReferenceResponseModel } from '../models/PagedIReferenceResponseModel';
import type { PagedMediaCollectionResponseModel } from '../models/PagedMediaCollectionResponseModel';
import type { PagedMediaRecycleBinItemResponseModel } from '../models/PagedMediaRecycleBinItemResponseModel';
import type { PagedMediaTreeItemResponseModel } from '../models/PagedMediaTreeItemResponseModel';
import type { PagedReferenceByIdModel } from '../models/PagedReferenceByIdModel';
import type { ReferenceByIdModel } from '../models/ReferenceByIdModel';
import type { SortingRequestModel } from '../models/SortingRequestModel';
import type { UpdateMediaRequestModel } from '../models/UpdateMediaRequestModel';
@@ -238,6 +240,64 @@ export class MediaResource {
});
}
/**
* @returns PagedIReferenceResponseModel Success
* @throws ApiError
*/
public static getMediaByIdReferencedBy({
id,
skip,
take = 20,
}: {
id: string,
skip?: number,
take?: number,
}): CancelablePromise<PagedIReferenceResponseModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/media/{id}/referenced-by',
path: {
'id': id,
},
query: {
'skip': skip,
'take': take,
},
errors: {
401: `The resource is protected and requires an authentication token`,
},
});
}
/**
* @returns PagedReferenceByIdModel Success
* @throws ApiError
*/
public static getMediaByIdReferencedDescendants({
id,
skip,
take = 20,
}: {
id: string,
skip?: number,
take?: number,
}): CancelablePromise<PagedReferenceByIdModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/media/{id}/referenced-descendants',
path: {
'id': id,
},
query: {
'skip': skip,
'take': take,
},
errors: {
401: `The resource is protected and requires an authentication token`,
},
});
}
/**
* @returns string Success
* @throws ApiError
@@ -267,6 +327,33 @@ export class MediaResource {
});
}
/**
* @returns PagedReferenceByIdModel Success
* @throws ApiError
*/
public static getMediaAreReferenced({
id,
skip,
take = 20,
}: {
id?: Array<string>,
skip?: number,
take?: number,
}): CancelablePromise<PagedReferenceByIdModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/media/are-referenced',
query: {
'id': id,
'skip': skip,
'take': take,
},
errors: {
401: `The resource is protected and requires an authentication token`,
},
});
}
/**
* @returns any Success
* @throws ApiError

View File

@@ -10,38 +10,6 @@ import { request as __request } from '../core/request';
export class RelationResource {
/**
* @returns PagedRelationResponseModel Success
* @throws ApiError
*/
public static getRelationChildRelationByChildId({
childId,
skip,
take = 100,
relationTypeAlias = '',
}: {
childId: string,
skip?: number,
take?: number,
relationTypeAlias?: string,
}): CancelablePromise<PagedRelationResponseModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/relation/child-relation/{childId}',
path: {
'childId': childId,
},
query: {
'skip': skip,
'take': take,
'relationTypeAlias': relationTypeAlias,
},
errors: {
401: `The resource is protected and requires an authentication token`,
},
});
}
/**
* @returns PagedRelationResponseModel Success
* @throws ApiError

View File

@@ -2,11 +2,9 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { CreateRelationTypeRequestModel } from '../models/CreateRelationTypeRequestModel';
import type { PagedRelationTypeTreeItemResponseModel } from '../models/PagedRelationTypeTreeItemResponseModel';
import type { PagedRelationTypeResponseModel } from '../models/PagedRelationTypeResponseModel';
import type { RelationTypeItemResponseModel } from '../models/RelationTypeItemResponseModel';
import type { RelationTypeResponseModel } from '../models/RelationTypeResponseModel';
import type { UpdateRelationTypeRequestModel } from '../models/UpdateRelationTypeRequestModel';
import type { CancelablePromise } from '../core/CancelablePromise';
import { OpenAPI } from '../core/OpenAPI';
@@ -36,22 +34,24 @@ export class RelationTypeResource {
}
/**
* @returns string Created
* @returns PagedRelationTypeResponseModel Success
* @throws ApiError
*/
public static postRelationType({
requestBody,
public static getRelationType({
skip,
take = 100,
}: {
requestBody?: CreateRelationTypeRequestModel,
}): CancelablePromise<string> {
skip?: number,
take?: number,
}): CancelablePromise<PagedRelationTypeResponseModel> {
return __request(OpenAPI, {
method: 'POST',
method: 'GET',
url: '/umbraco/management/api/v1/relation-type',
body: requestBody,
mediaType: 'application/json',
responseHeader: 'Umb-Generated-Resource',
query: {
'skip': skip,
'take': take,
},
errors: {
400: `Bad Request`,
401: `The resource is protected and requires an authentication token`,
},
});
@@ -79,78 +79,4 @@ export class RelationTypeResource {
});
}
/**
* @returns string Success
* @throws ApiError
*/
public static deleteRelationTypeById({
id,
}: {
id: string,
}): CancelablePromise<string> {
return __request(OpenAPI, {
method: 'DELETE',
url: '/umbraco/management/api/v1/relation-type/{id}',
path: {
'id': id,
},
responseHeader: 'Umb-Notifications',
errors: {
401: `The resource is protected and requires an authentication token`,
404: `Not Found`,
},
});
}
/**
* @returns any Success
* @throws ApiError
*/
public static putRelationTypeById({
id,
requestBody,
}: {
id: string,
requestBody?: UpdateRelationTypeRequestModel,
}): CancelablePromise<RelationTypeResponseModel> {
return __request(OpenAPI, {
method: 'PUT',
url: '/umbraco/management/api/v1/relation-type/{id}',
path: {
'id': id,
},
body: requestBody,
mediaType: 'application/json',
errors: {
400: `Bad Request`,
401: `The resource is protected and requires an authentication token`,
404: `Not Found`,
},
});
}
/**
* @returns PagedRelationTypeTreeItemResponseModel Success
* @throws ApiError
*/
public static getTreeRelationTypeRoot({
skip,
take = 100,
}: {
skip?: number,
take?: number,
}): CancelablePromise<PagedRelationTypeTreeItemResponseModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/tree/relation-type/root',
query: {
'skip': skip,
'take': take,
},
errors: {
401: `The resource is protected and requires an authentication token`,
},
});
}
}

View File

@@ -1,107 +0,0 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { PagedRelationItemResponseModel } from '../models/PagedRelationItemResponseModel';
import type { CancelablePromise } from '../core/CancelablePromise';
import { OpenAPI } from '../core/OpenAPI';
import { request as __request } from '../core/request';
export class TrackedReferenceResource {
/**
* @returns PagedRelationItemResponseModel Success
* @throws ApiError
*/
public static getTrackedReferenceById({
id,
skip,
take = 20,
filterMustBeIsDependency = false,
}: {
id: string,
skip?: number,
take?: number,
filterMustBeIsDependency?: boolean,
}): CancelablePromise<PagedRelationItemResponseModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/tracked-reference/{id}',
path: {
'id': id,
},
query: {
'skip': skip,
'take': take,
'filterMustBeIsDependency': filterMustBeIsDependency,
},
errors: {
401: `The resource is protected and requires an authentication token`,
},
});
}
/**
* @returns PagedRelationItemResponseModel Success
* @throws ApiError
*/
public static getTrackedReferenceDescendantsByParentId({
parentId,
skip,
take = 20,
filterMustBeIsDependency = true,
}: {
parentId: string,
skip?: number,
take?: number,
filterMustBeIsDependency?: boolean,
}): CancelablePromise<PagedRelationItemResponseModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/tracked-reference/descendants/{parentId}',
path: {
'parentId': parentId,
},
query: {
'skip': skip,
'take': take,
'filterMustBeIsDependency': filterMustBeIsDependency,
},
errors: {
401: `The resource is protected and requires an authentication token`,
},
});
}
/**
* @returns PagedRelationItemResponseModel Success
* @throws ApiError
*/
public static getTrackedReferenceItem({
id,
skip,
take = 20,
filterMustBeIsDependency = true,
}: {
id?: Array<string>,
skip?: number,
take?: number,
filterMustBeIsDependency?: boolean,
}): CancelablePromise<PagedRelationItemResponseModel> {
return __request(OpenAPI, {
method: 'GET',
url: '/umbraco/management/api/v1/tracked-reference/item',
query: {
'id': id,
'skip': skip,
'take': take,
'filterMustBeIsDependency': filterMustBeIsDependency,
},
errors: {
401: `The resource is protected and requires an authentication token`,
},
});
}
}

View File

@@ -31,11 +31,9 @@ import { handlers as stylesheetHandlers } from './handlers/stylesheet/index.js';
import { handlers as tagHandlers } from './handlers/tag-handlers.js';
import { handlers as telemetryHandlers } from './handlers/telemetry.handlers.js';
import { handlers as templateHandlers } from './handlers/template/index.js';
import { handlers as trackedReferenceHandlers } from './handlers/tracked-reference.handlers.js';
import { handlers as upgradeHandlers } from './handlers/upgrade.handlers.js';
import { handlers as userGroupsHandlers } from './handlers/user-group/index.js';
import { handlers as userHandlers } from './handlers/user/index.js';
import { relationHandlers, relationTypeHandlers } from './handlers/relations/index.js';
import * as manifestsHandlers from './handlers/manifests.handlers.js';
import * as serverHandlers from './handlers/server.handlers.js';
@@ -66,8 +64,6 @@ const handlers = [
...profilingHandlers,
...publishedStatusHandlers,
...redirectManagementHandlers,
...relationHandlers,
...relationTypeHandlers,
...rteEmbedHandlers,
...scriptHandlers,
...staticFileHandlers,
@@ -75,7 +71,6 @@ const handlers = [
...tagHandlers,
...telemetryHandlers,
...templateHandlers,
...trackedReferenceHandlers,
...upgradeHandlers,
...userGroupsHandlers,
...userHandlers,

View File

@@ -17,6 +17,7 @@ import type {
DocumentResponseModel,
DocumentTreeItemResponseModel,
DomainsResponseModel,
DocumentConfigurationResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
export class UmbDocumentMockDB extends UmbEntityMockDbBase<UmbMockDocumentModel> {
@@ -39,6 +40,17 @@ export class UmbDocumentMockDB extends UmbEntityMockDbBase<UmbMockDocumentModel>
getDomainsForDocument(id: string): DomainsResponseModel {
return { defaultIsoCode: 'en-us', domains: [] };
}
getConfiguration(): DocumentConfigurationResponseModel {
return {
allowEditInvariantFromNonDefault: true,
allowNonExistingSegmentsCreation: true,
disableDeleteWhenReferenced: true,
disableUnpublishWhenReferenced: true,
reservedFieldNames: [],
sanitizeTinyMce: true,
};
}
}
const treeItemMapper = (model: UmbMockDocumentModel): DocumentTreeItemResponseModel => {

View File

@@ -24,6 +24,8 @@ export const data: Array<UmbMockMemberTypeModel> = [
alias: 'prop1',
name: 'Prop 1',
description: null,
isSensitive: false,
visibility: { memberCanEdit: true, memberCanView: true },
dataType: { id: '0cc0eba1-9960-42c9-bf9b-60e150b429ae' },
variesByCulture: false,
variesBySegment: false,

View File

@@ -1,139 +0,0 @@
import { UmbEntityData } from '../entity.data.js';
import { createEntityTreeItem } from '../utils.js';
import type {
EntityTreeItemResponseModel,
NamedEntityTreeItemResponseModel,
RelationTypeResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
export const data: Array<RelationTypeResponseModel> = [
{
id: 'e0d39ff5-71d8-453f-b682-9d8d31ee5e06',
alias: 'relateDocumentOnCopy',
name: 'Relate Document On Copy',
path: '',
isDeletable: true,
isBidirectional: false,
isDependency: false,
parentObjectType: 'Document',
childObjectType: 'Document',
parentObjectTypeName: 'Document',
childObjectTypeName: 'Document',
},
{
id: 'ac68cde6-763f-4231-a751-1101b57defd2',
alias: 'relateParentDocumentOnDelete',
name: 'Relate Parent Document On Delete',
path: '',
isDeletable: true,
isBidirectional: false,
isDependency: false,
parentObjectType: 'Document',
childObjectType: 'Document',
parentObjectTypeName: 'Document',
childObjectTypeName: 'Document',
},
{
id: '6f9b800c-762c-42d4-85d9-bf40a77d689e',
alias: 'relateParentMediaFolderOnDelete',
name: 'Relate Parent Media Folder On Delete',
path: '',
isDeletable: true,
isBidirectional: false,
isDependency: false,
parentObjectType: 'Document',
childObjectType: 'Document',
parentObjectTypeName: 'Document',
childObjectTypeName: 'Document',
},
{
id: 'd421727d-43de-4205-b4c6-037404f309ad',
alias: 'relatedMedia',
name: 'Related Media',
path: '',
isDeletable: true,
isBidirectional: false,
isDependency: false,
parentObjectType: 'Document',
childObjectType: 'Document',
parentObjectTypeName: 'Document',
childObjectTypeName: 'Document',
},
{
id: 'e9a0a28e-2d5b-4229-ac00-66f2df230513',
alias: 'relatedDocument',
name: 'Related Document',
path: '',
isDeletable: true,
isBidirectional: false,
isDependency: false,
parentObjectType: 'Document',
childObjectType: 'Document',
parentObjectTypeName: 'Document',
childObjectTypeName: 'Document',
},
];
export const treeData: Array<NamedEntityTreeItemResponseModel> = [
{
id: 'e0d39ff5-71d8-453f-b682-9d8d31ee5e06',
parent: null,
name: 'Relate Document On Copy',
hasChildren: false,
},
{
id: 'ac68cde6-763f-4231-a751-1101b57defd2',
parent: null,
name: 'Relate Parent Document On Delete',
hasChildren: false,
},
{
id: '6f9b800c-762c-42d4-85d9-bf40a77d689e',
parent: null,
name: 'Relate Parent Media Folder On Delete',
hasChildren: false,
},
{
id: 'd421727d-43de-4205-b4c6-037404f309ad',
parent: null,
name: 'Related Media',
hasChildren: false,
},
{
id: 'e9a0a28e-2d5b-4229-ac00-66f2df230513',
parent: null,
name: 'Related Document',
hasChildren: false,
},
];
// Temp mocked database
// TODO: all properties are optional in the server schema. I don't think this is correct.
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
class UmbRelationTypeData extends UmbEntityData<RelationTypeResponseModel> {
private treeData = treeData;
constructor() {
super(data);
}
//TODO Can relation types have children?
getTreeRoot(): Array<EntityTreeItemResponseModel> {
const rootItems = this.treeData;
return rootItems.map((item) => createEntityTreeItem(item));
}
//TODO Can relation types have children?
getTreeItemChildren(id: string): Array<EntityTreeItemResponseModel> {
const childItems = this.treeData.filter((item) => item.parent?.id === id);
return childItems.map((item) => createEntityTreeItem(item));
}
getTreeItem(ids: Array<string>): Array<EntityTreeItemResponseModel> {
const items = this.treeData.filter((item) => ids.includes(item.id ?? ''));
return items.map((item) => createEntityTreeItem(item));
}
}
export const umbRelationTypeData = new UmbRelationTypeData();

View File

@@ -1,109 +0,0 @@
import { UmbEntityData } from '../entity.data.js';
import type { RelationResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
export const data: Array<RelationResponseModel> = [
{
parentId: 'e0d39ff5-71d8-453f-b682-9d8d31ee5e06',
parentName: 'Relate Document On Copy',
childId: '1',
childName: 'Child 1',
createDate: '2021-01-01',
comment: 'Comment 1',
},
{
parentId: 'e0d39ff5-71d8-453f-b682-9d8d31ee5e06',
parentName: 'Relate Document On Copy',
childId: '2',
childName: 'Child 2',
createDate: '2021-01-01',
comment: 'Comment 2',
},
{
parentId: 'e0d39ff5-71d8-453f-b682-9d8d31ee5e06',
parentName: 'Relate Document On Copy',
childId: '3',
childName: 'Child 3',
createDate: '2021-01-01',
comment: 'Comment 3',
},
{
parentId: 'e0d39ff5-71d8-453f-b682-9d8d31ee5e06',
parentName: 'Relate Document On Copy',
childId: '4',
childName: 'Child 4',
createDate: '2021-01-01',
comment: 'Comment 4',
},
{
parentId: 'ac68cde6-763f-4231-a751-1101b57defd2',
parentName: 'Relate Document On Copy',
childId: '5',
childName: 'Child 5',
createDate: '2021-01-01',
comment: 'Comment 5',
},
{
parentId: 'ac68cde6-763f-4231-a751-1101b57defd2',
parentName: 'Relate Document On Copy',
childId: '6',
childName: 'Child 6',
createDate: '2021-01-01',
comment: 'Comment 6',
},
{
parentId: '6f9b800c-762c-42d4-85d9-bf40a77d689e',
parentName: 'Relate Document On Copy',
childId: '7',
childName: 'Child 7',
createDate: '2021-01-01',
comment: 'Comment 7',
},
{
parentId: 'd421727d-43de-4205-b4c6-037404f309ad',
parentName: 'Relate Document On Copy',
childId: '8',
childName: 'Child 8',
createDate: '2021-01-01',
comment: 'Comment 8',
},
{
parentId: 'd421727d-43de-4205-b4c6-037404f309ad',
parentName: 'Relate Document On Copy',
childId: '9',
childName: 'Child 9',
createDate: '2021-01-01',
comment: 'Comment 9',
},
{
parentId: 'e9a0a28e-2d5b-4229-ac00-66f2df230513',
parentName: 'Relate Document On Copy',
childId: '10',
childName: 'Child 10',
createDate: '2021-01-01',
comment: 'Comment 10',
},
{
parentId: 'e9a0a28e-2d5b-4229-ac00-66f2df230513',
parentName: 'Relate Document On Copy',
childId: '11',
childName: 'Child 11',
createDate: '2021-01-01',
comment: 'Comment 11',
},
];
// Temp mocked database
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
class UmbRelationData extends UmbEntityData<RelationResponseModel> {
constructor() {
super(data);
}
getRelationsByParentId(id: string) {
const test = this.data.filter((relation) => relation.parentId === id);
return { items: test, total: test.length };
}
}
export const umbRelationData = new UmbRelationData();

View File

@@ -1,28 +1,45 @@
import type { RelationItemResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
import type {
DefaultReferenceResponseModel,
DocumentReferenceResponseModel,
MediaReferenceResponseModel,
} from '@umbraco-cms/backoffice/external/backend-api';
export const items: Array<RelationItemResponseModel> = [
export const items: Array<
DefaultReferenceResponseModel | DocumentReferenceResponseModel | MediaReferenceResponseModel
> = [
{
nodeId: 'simple-document-id',
nodeName: 'Simple Document',
nodeType: 'document',
nodePublished: true,
contentTypeIcon: 'icon-document',
contentTypeName: 'Simple Document Type',
contentTypeAlias: 'blogPost',
relationTypeIsBidirectional: false,
relationTypeIsDependency: true,
relationTypeName: 'Related Document',
},
id: 'simple-document-id',
name: 'Simple Document',
published: true,
documentType: {
alias: 'blogPost',
icon: 'icon-document',
name: 'Simple Document Type',
},
} satisfies DocumentReferenceResponseModel,
{
nodeId: '1234',
nodeName: 'Image Block',
nodeType: 'element',
nodePublished: true,
contentTypeIcon: 'icon-settings',
contentTypeName: 'Image Block',
contentTypeAlias: 'imageBlock',
relationTypeIsBidirectional: false,
relationTypeIsDependency: true,
relationTypeName: 'Related Document',
},
id: '1234',
name: 'Image Block',
published: true,
documentType: {
alias: 'imageBlock',
icon: 'icon-settings',
name: 'Image Block',
},
} satisfies DocumentReferenceResponseModel,
{
id: 'media-id',
name: 'Simple Media',
mediaType: {
alias: 'image',
icon: 'icon-picture',
name: 'Image',
},
} satisfies MediaReferenceResponseModel,
{
id: 'default-id',
name: 'Some other reference',
type: 'Default',
icon: 'icon-bug',
} satisfies DefaultReferenceResponseModel,
];

View File

@@ -61,6 +61,7 @@ class UmbUserMockDB extends UmbEntityMockDbBase<UmbMockUserModel> {
name: firstUser.name,
email: firstUser.email,
userName: firstUser.email,
hasAccessToSensitiveData: true,
avatarUrls: [],
hasAccessToAllLanguages: true,
languageIsoCode: firstUser.languageIsoCode,

View File

@@ -16,7 +16,6 @@ import { handlers as languageHandlers } from './handlers/language/index.js';
import { handlers as redirectManagementHandlers } from './handlers/redirect-management.handlers.js';
import { handlers as packageHandlers } from './handlers/package.handlers.js';
import { handlers as configHandlers } from './handlers/config.handlers.js';
import { handlers as trackedReferenceHandlers } from './handlers/tracked-reference.handlers.js';
export const handlers = [
serverHandlers.serverRunningHandler,
@@ -38,5 +37,4 @@ export const handlers = [
...redirectManagementHandlers,
...packageHandlers,
...configHandlers,
...trackedReferenceHandlers,
];

View File

@@ -1,8 +1,10 @@
const { rest } = window.MockServiceWorker;
import { umbDocumentMockDb } from '../../data/document/document.db.js';
import { items as referenceData } from '../../data/tracked-reference.data.js';
import { UMB_SLUG } from './slug.js';
import type {
CreateDocumentRequestModel,
PagedIReferenceResponseModel,
UpdateDocumentRequestModel,
} from '@umbraco-cms/backoffice/external/backend-api';
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
@@ -23,6 +25,22 @@ export const detailHandlers = [
);
}),
rest.get(umbracoPath(`${UMB_SLUG}/configuration`), (_req, res, ctx) => {
return res(ctx.status(200), ctx.json(umbDocumentMockDb.getConfiguration()));
}),
rest.get(umbracoPath(`${UMB_SLUG}/:id/referenced-by`), (_req, res, ctx) => {
const id = _req.params.id as string;
if (!id) return;
const PagedTrackedReference = {
total: referenceData.length,
items: referenceData,
};
return res(ctx.status(200), ctx.json<PagedIReferenceResponseModel>(PagedTrackedReference));
}),
rest.get(umbracoPath(`${UMB_SLUG}/:id`), (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return res(ctx.status(400));

View File

@@ -1,7 +1,12 @@
const { rest } = window.MockServiceWorker;
import { umbMediaMockDb } from '../../data/media/media.db.js';
import { items as referenceData } from '../../data/tracked-reference.data.js';
import { UMB_SLUG } from './slug.js';
import type { CreateMediaRequestModel, UpdateMediaRequestModel } from '@umbraco-cms/backoffice/external/backend-api';
import type {
CreateMediaRequestModel,
PagedIReferenceResponseModel,
UpdateMediaRequestModel,
} from '@umbraco-cms/backoffice/external/backend-api';
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
export const detailHandlers = [
@@ -20,6 +25,18 @@ export const detailHandlers = [
);
}),
rest.get(umbracoPath(`${UMB_SLUG}/:id/referenced-by`), (_req, res, ctx) => {
const id = _req.params.id as string;
if (!id) return;
const PagedTrackedReference = {
total: referenceData.length,
items: referenceData,
};
return res(ctx.status(200), ctx.json<PagedIReferenceResponseModel>(PagedTrackedReference));
}),
rest.get(umbracoPath(`${UMB_SLUG}/:id`), (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return res(ctx.status(400));

View File

@@ -1,2 +0,0 @@
export * from './relation/index.js';
export * from './relation-type/index.js';

View File

@@ -1,47 +0,0 @@
const { rest } = window.MockServiceWorker;
import { umbRelationTypeData } from '../../../data/relations/relation-type.data.js';
import { UMB_SLUG } from './slug.js';
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
// TODO: add schema
export const handlers = [
rest.delete<string[]>(umbracoPath(`${UMB_SLUG}/:id`), async (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return;
umbRelationTypeData.delete([id]);
return res(ctx.status(200));
}),
rest.get(umbracoPath(`${UMB_SLUG}/:id`), (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return;
const RelationType = umbRelationTypeData.getById(id);
return res(ctx.status(200), ctx.json(RelationType));
}),
rest.post(umbracoPath(`${UMB_SLUG}/:id`), async (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return;
const data = await req.json();
if (!data) return;
umbRelationTypeData.insert(data);
return res(ctx.status(200));
}),
rest.put(umbracoPath(`${UMB_SLUG}/:id`), async (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return;
const data = await req.json();
if (!data) return;
umbRelationTypeData.save(id, data);
return res(ctx.status(200));
}),
];

View File

@@ -1,4 +0,0 @@
import { handlers as detailHandlers } from './detail.handlers.js';
import { handlers as treeHandlers } from './tree.handlers.js';
export const relationTypeHandlers = [...detailHandlers, ...treeHandlers];

View File

@@ -1 +0,0 @@
export const UMB_SLUG = '/relation-type';

View File

@@ -1,36 +0,0 @@
const { rest } = window.MockServiceWorker;
import { umbRelationTypeData } from '../../../data/relations/relation-type.data.js';
import { UMB_SLUG } from './slug.js';
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
export const handlers = [
rest.get(umbracoPath(`/tree${UMB_SLUG}/root`), (req, res, ctx) => {
const rootItems = umbRelationTypeData.getTreeRoot();
const response = {
total: rootItems.length,
items: rootItems,
};
return res(ctx.status(200), ctx.json(response));
}),
rest.get(umbracoPath(`/tree${UMB_SLUG}/children`), (req, res, ctx) => {
const parentId = req.url.searchParams.get('parentId');
if (!parentId) return;
const children = umbRelationTypeData.getTreeItemChildren(parentId);
const response = {
total: children.length,
items: children,
};
return res(ctx.status(200), ctx.json(response));
}),
rest.get(umbracoPath(`/tree${UMB_SLUG}/item`), (req, res, ctx) => {
const ids = req.url.searchParams.getAll('id');
if (!ids) return;
const items = umbRelationTypeData.getTreeItem(ids);
return res(ctx.status(200), ctx.json(items));
}),
];

View File

@@ -1,3 +0,0 @@
import { handlers as itemHandlers } from './item.handlers.js';
export const relationHandlers = [...itemHandlers];

View File

@@ -1,15 +0,0 @@
const { rest } = window.MockServiceWorker;
import { umbRelationData } from '../../../data/relations/relation.data.js';
import { UMB_SLUG } from './slug.js';
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
export const handlers = [
rest.get(umbracoPath(`${UMB_SLUG}/type/:id`), (req, res, ctx) => {
const id = req.params.id as string;
if (!id) return;
const response = umbRelationData.getRelationsByParentId(id);
return res(ctx.status(200), ctx.json(response));
}),
];

View File

@@ -1 +0,0 @@
export const UMB_SLUG = '/relation';

View File

@@ -1,18 +0,0 @@
import { items } from '../data/tracked-reference.data.js';
const { rest } = window.MockServiceWorker;
import { umbracoPath } from '@umbraco-cms/backoffice/utils';
import type { PagedRelationItemResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
export const handlers = [
rest.get(umbracoPath('/tracked-reference/:id'), (_req, res, ctx) => {
const id = _req.params.id as string;
if (!id) return;
const PagedTrackedReference = {
total: items.length,
items: items,
};
return res(ctx.status(200), ctx.json<PagedRelationItemResponseModel>(PagedTrackedReference));
}),
];

View File

@@ -1,10 +1,10 @@
import { UMB_DEFAULT_COLLECTION_CONTEXT, UmbDefaultCollectionContext } from './collection-default.context.js';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { PropertyValueMap } from '@umbraco-cms/backoffice/external/lit';
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import type { UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { PropertyValueMap } from '@umbraco-cms/backoffice/external/lit';
import type { UmbBackofficeManifestKind } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbRoute } from '@umbraco-cms/backoffice/router';
const manifest: UmbBackofficeManifestKind = {
@@ -30,8 +30,8 @@ export class UmbCollectionDefaultElement extends UmbLitElement {
constructor() {
super();
this.consumeContext(UMB_DEFAULT_COLLECTION_CONTEXT, (instance) => {
this.#collectionContext = instance;
this.consumeContext(UMB_DEFAULT_COLLECTION_CONTEXT, (context) => {
this.#collectionContext = context;
this.#observeCollectionRoutes();
});
}
@@ -44,10 +44,13 @@ export class UmbCollectionDefaultElement extends UmbLitElement {
#observeCollectionRoutes() {
if (!this.#collectionContext) return;
this.observe(this.#collectionContext.view.routes, (routes) => {
this._routes = routes;
}),
'umbCollectionRoutesObserver';
this.observe(
this.#collectionContext.view.routes,
(routes) => {
this._routes = routes;
},
'umbCollectionRoutesObserver',
);
}
render() {

View File

@@ -14,6 +14,7 @@ export interface UmbCollectionConfiguration {
unique?: string;
dataTypeId?: string;
allowedEntityBulkActions?: UmbCollectionBulkActionPermissions;
layouts?: Array<UmbCollectionLayoutConfiguration>;
orderBy?: string;
orderDirection?: string;
pageSize?: number;
@@ -31,6 +32,12 @@ export interface UmbCollectionColumnConfiguration {
nameTemplate?: string;
}
export interface UmbCollectionLayoutConfiguration {
icon?: string;
name: string;
collectionView: string;
}
export interface UmbCollectionContext {
setConfig(config: UmbCollectionConfiguration): void;
getConfig(): UmbCollectionConfiguration | undefined;

View File

@@ -1,4 +1,4 @@
import type { TemporaryFileQueueItem } from '../../temporary-file/temporary-file-manager.class.js';
import type { UmbTemporaryFileModel } from '../../temporary-file/temporary-file-manager.class.js';
import { UmbTemporaryFileManager } from '../../temporary-file/temporary-file-manager.class.js';
import { UMB_PROPERTY_DATASET_CONTEXT } from '../../property/property-dataset/property-dataset-context.token.js';
import { UmbId } from '@umbraco-cms/backoffice/id';
@@ -60,7 +60,7 @@ export class UmbInputUploadFieldElement extends FormControlMixin(UmbLitElement)
_files: Array<{
path: string;
unique: string;
queueItem?: TemporaryFileQueueItem;
queueItem?: UmbTemporaryFileModel;
file?: File;
}> = [];
@@ -93,8 +93,8 @@ export class UmbInputUploadFieldElement extends FormControlMixin(UmbLitElement)
this.#serverUrl = instance.getServerUrl();
}).asPromise();
this.observe(this.#manager.isReady, (value) => (this.error = !value));
this.observe(this.#manager.queue, (value) => {
this.error = !value.length;
this._files = this._files.map((file) => {
const queueItem = value.find((item) => item.unique === file.unique);
if (queueItem) {
@@ -144,7 +144,7 @@ export class UmbInputUploadFieldElement extends FormControlMixin(UmbLitElement)
#setFiles(files: File[]) {
const items = files.map(
(file): TemporaryFileQueueItem => ({
(file): UmbTemporaryFileModel => ({
unique: UmbId.new(),
file,
status: 'waiting',
@@ -216,7 +216,7 @@ export class UmbInputUploadFieldElement extends FormControlMixin(UmbLitElement)
);
}
#renderFile(file: { path: string; unique: string; queueItem?: TemporaryFileQueueItem; file?: File }) {
#renderFile(file: { path: string; unique: string; queueItem?: UmbTemporaryFileModel; file?: File }) {
// TODO: Get the mime type from the server and use that to determine the file type.
const type = this.#getFileTypeFromPath(file.path);

View File

@@ -264,8 +264,6 @@ export class UmbTableElement extends LitElement {
css`
:host {
height: fit-content;
padding: var(--uui-size-space-4);
padding-top: 0;
}
uui-table {

View File

@@ -3,6 +3,7 @@ export * from './change.event.js';
export * from './delete.event.js';
export * from './deselected.event.js';
export * from './input.event.js';
export * from './progress.event.js';
export * from './selected.event.js';
export * from './selection-change.event.js';
export * from './request-reload-structure-for-entity.event.js';

View File

@@ -0,0 +1,9 @@
export class UmbProgressEvent extends Event {
public static readonly TYPE = 'progress';
public progress: number;
public constructor(progress: number) {
super(UmbProgressEvent.TYPE, { bubbles: true, composed: false, cancelable: false });
this.progress = progress;
}
}

View File

@@ -70,16 +70,16 @@ export class UmbIconPickerModalElement extends UmbModalBaseElement<UmbIconPicker
${this.renderSearchbar()}
<hr />
<uui-color-swatches
.value="${this._modalValue?.color ?? ''}"
.value=${this._currentAlias}
label="Color switcher for icons"
@change="${this.#onColorChange}">
@change=${this.#onColorChange}>
${
// TODO: Missing translation for the color aliases.
this._colorList.map(
(color) => html`
<uui-color-swatch
label="${color.alias}"
title="${color.alias}"
label=${color.alias}
title=${color.alias}
value=${color.alias}
style="--uui-swatch-color: var(${color.varName})"></uui-color-swatch>
`,

View File

@@ -1,18 +1,28 @@
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { html, customElement, property, repeat, css, ifDefined } from '@umbraco-cms/backoffice/external/lit';
import type { UUIBooleanInputEvent, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
import {
html,
customElement,
property,
repeat,
css,
ifDefined,
nothing,
when,
} from '@umbraco-cms/backoffice/external/lit';
import { extractUmbColorVariable } from '@umbraco-cms/backoffice/resources';
import { UMB_ICON_PICKER_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbPropertyValueChangeEvent } from '@umbraco-cms/backoffice/property-editor';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_ICON_PICKER_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
import type { UmbInputManifestElement } from '@umbraco-cms/backoffice/components';
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import type { UUIInputElement, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
interface LayoutConfig {
interface UmbCollectionLayoutConfig {
icon?: string;
isSystem?: boolean;
name?: string;
path?: string;
collectionView?: string;
isSystem?: boolean;
selected?: boolean;
}
@@ -24,14 +34,41 @@ export class UmbPropertyEditorUICollectionViewLayoutConfigurationElement
extends UmbLitElement
implements UmbPropertyEditorUiElement
{
// TODO: [LK] Add sorting.
@property({ type: Array })
value?: Array<LayoutConfig>;
value?: Array<UmbCollectionLayoutConfig>;
@property({ type: Object, attribute: false })
public config?: UmbPropertyEditorConfigCollection;
#onAdd() {
this.value = [...(this.value ?? []), { isSystem: false, icon: 'icon-stop', selected: true }];
async #focusNewItem() {
await this.updateComplete;
const input = this.shadowRoot?.querySelector('.layout-item:last-of-type > uui-input') as UUIInputElement;
input.focus();
}
#onAdd(event: { target: UmbInputManifestElement }) {
const manifest = event.target.value;
this.value = [
...(this.value ?? []),
{
icon: manifest?.icon,
name: manifest?.label,
collectionView: manifest?.value,
},
];
this.dispatchEvent(new UmbPropertyValueChangeEvent());
this.#focusNewItem();
}
#onChangeLabel(e: UUIInputEvent, index: number) {
const values = [...(this.value ?? [])];
values[index] = { ...values[index], name: e.target.value as string };
this.value = values;
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
@@ -42,34 +79,9 @@ export class UmbPropertyEditorUICollectionViewLayoutConfigurationElement
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
#onChangePath(e: UUIInputEvent, index: number) {
const values = [...(this.value ?? [])];
values[index] = { ...values[index], path: e.target.value as string };
this.value = values;
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
#onChangeName(e: UUIInputEvent, index: number) {
const values = [...(this.value ?? [])];
values[index] = { ...values[index], name: e.target.value as string };
this.value = values;
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
#onChangeSelected(e: UUIBooleanInputEvent, index: number) {
const values = [...(this.value ?? [])];
values[index] = { ...values[index], selected: e.target.checked };
this.value = values;
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
async #onIconChange(index: number) {
// This is not begin used? [NL]
//const icon = this.#iconReader((this.value ? this.value[index].icon : undefined) ?? '');
// TODO: send icon data to modal
async #onIconChange(icon: typeof UMB_ICON_PICKER_MODAL.VALUE, index: number) {
const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
const modal = modalManager.open(this, UMB_ICON_PICKER_MODAL);
const modal = modalManager.open(this, UMB_ICON_PICKER_MODAL, { value: icon });
const picked = await modal?.onSubmit();
if (!picked) return;
@@ -79,81 +91,59 @@ export class UmbPropertyEditorUICollectionViewLayoutConfigurationElement
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
#parseIcon(iconString: string | undefined): typeof UMB_ICON_PICKER_MODAL.VALUE {
const [icon, color] = iconString?.split(' ') ?? [];
return { icon, color: color?.replace('color-', '') };
}
render() {
return html`<div id="layout-wrapper">
${this.value
? repeat(
this.value,
(layout, index) => '' + layout.name + layout.icon,
(layout, index) =>
html` <div class="layout-item">
<uui-icon name="icon-navigation"></uui-icon> ${layout.isSystem
? this.renderSystemFieldRow(layout, index)
: this.renderCustomFieldRow(layout, index)}
</div>`,
)
: ''}
if (!this.value) return nothing;
return html`
<div id="layout-wrapper">
${repeat(
this.value,
(layout, index) => '' + index + layout.name + layout.icon,
(layout, index) => this.#renderLayout(layout, index),
)}
</div>
<uui-button
id="add"
label=${this.localize.term('general_add')}
look="placeholder"
@click=${this.#onAdd}></uui-button>`;
<umb-input-manifest extension-type="collectionView" @change=${this.#onAdd}></umb-input-manifest>
`;
}
#iconReader(iconString: string): { icon: string; color?: string } {
if (!iconString) return { icon: '' };
#renderLayout(layout: UmbCollectionLayoutConfig, index: number) {
const icon = this.#parseIcon(layout.icon);
const varName = icon.color ? extractUmbColorVariable(icon.color) : undefined;
const parts = iconString.split(' ');
return html`
<div class="layout-item">
<uui-icon name="icon-navigation"></uui-icon>
if (parts.length === 2) {
const [icon, color] = parts;
const varName = extractUmbColorVariable(color.replace('color-', ''));
return { icon, color: varName };
} else {
const [icon] = parts;
return { icon };
}
}
<uui-button compact look="outline" label="pick icon" @click=${() => this.#onIconChange(icon, index)}>
${when(
icon.color,
() => html`<uui-icon name=${ifDefined(icon.icon)} style="color:var(${varName})"></uui-icon>`,
() => html`<uui-icon name=${ifDefined(icon.icon)}></uui-icon>`,
)}
</uui-button>
renderSystemFieldRow(layout: LayoutConfig, index: number) {
const icon = this.#iconReader(layout.icon ?? '');
<uui-input
label="name"
value=${ifDefined(layout.name)}
placeholder="Enter a label..."
@change=${(e: UUIInputEvent) => this.#onChangeLabel(e, index)}></uui-input>
return html` <uui-button compact disabled label="Icon" look="outline">
<uui-icon name=${ifDefined(icon.icon)}></uui-icon>
</uui-button>
${index}
<span><strong>${ifDefined(layout.name)}</strong> <small>(system field)</small></span>
<uui-checkbox
?checked=${layout.selected}
label="Show"
@change=${(e: UUIBooleanInputEvent) => this.#onChangeSelected(e, index)}>
</uui-checkbox>`;
}
<div class="alias">
<code>${layout.collectionView}</code>
</div>
renderCustomFieldRow(layout: LayoutConfig, index: number) {
const icon = this.#iconReader(layout.icon ?? '');
return html`<uui-button compact look="outline" label="pick icon" @click=${() => this.#onIconChange(index)}>
${icon.color
? html`<uui-icon name=${icon.icon} style="color:var(${icon.color})"></uui-icon>`
: html`<uui-icon name=${icon.icon}></uui-icon>`}
</uui-button>
${index}
<uui-input
label="name"
value=${ifDefined(layout.name)}
placeholder="Name..."
@change=${(e: UUIInputEvent) => this.#onChangeName(e, index)}></uui-input>
<uui-input
label="path"
value=${ifDefined(layout.path)}
placeholder="Layout path..."
@change=${(e: UUIInputEvent) => this.#onChangePath(e, index)}></uui-input>
<uui-button
label=${this.localize.term('actions_remove')}
look="secondary"
@click=${() => this.#onRemove(index)}></uui-button>`;
<div class="actions">
<uui-button
label=${this.localize.term('general_remove')}
look="secondary"
@click=${() => this.#onRemove(index)}></uui-button>
</div>
</div>
`;
}
static styles = [
@@ -163,7 +153,7 @@ export class UmbPropertyEditorUICollectionViewLayoutConfigurationElement
display: flex;
flex-direction: column;
gap: 1px;
margin-bottom: var(--uui-size-3);
margin-bottom: var(--uui-size-1);
}
.layout-item {
@@ -174,12 +164,23 @@ export class UmbPropertyEditorUICollectionViewLayoutConfigurationElement
padding: var(--uui-size-3) var(--uui-size-6);
}
.layout-item > :last-child {
margin-left: auto;
.layout-item > uui-icon {
flex: 0 0 var(--uui-size-6);
}
#add {
width: 100%;
.layout-item > uui-button {
flex: 0 0 var(--uui-size-10);
}
.layout-item > uui-input,
.layout-item > .alias {
flex: 1;
}
.layout-item > .actions {
flex: 0 0 auto;
display: flex;
justify-content: flex-end;
}
`,
];

View File

@@ -1,14 +1,14 @@
import type { UmbDataSourceResponse } from '../data-source-response.interface.js';
import type { UmbReadDetailDataSource } from './read/index.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
export interface UmbDetailDataSourceConstructor<DetailType = any> {
new (host: UmbControllerHost): UmbDetailDataSource<DetailType>;
}
export interface UmbDetailDataSource<DetailType> {
export interface UmbDetailDataSource<DetailType> extends UmbReadDetailDataSource<DetailType> {
createScaffold(preset?: Partial<DetailType>): Promise<UmbDataSourceResponse<DetailType>>;
create(data: DetailType, parentUnique: string | null): Promise<UmbDataSourceResponse<DetailType>>;
read(unique: string): Promise<UmbDataSourceResponse<DetailType>>;
update(data: DetailType): Promise<UmbDataSourceResponse<DetailType>>;
delete(unique: string): Promise<UmbDataSourceResponse>;
}

View File

@@ -1,15 +1,9 @@
import type {
UmbRepositoryErrorResponse,
UmbRepositoryResponse,
UmbRepositoryResponseWithAsObservable,
} from '../types.js';
import type { UmbRepositoryErrorResponse, UmbRepositoryResponse } from '../types.js';
import type { UmbReadDetailRepository } from './read/index.js';
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
import type { Observable } from '@umbraco-cms/backoffice/external/rxjs';
export interface UmbDetailRepository<DetailModelType> extends UmbApi {
export interface UmbDetailRepository<DetailModelType> extends UmbReadDetailRepository<DetailModelType>, UmbApi {
createScaffold(preset?: Partial<DetailModelType>): Promise<UmbRepositoryResponse<DetailModelType>>;
requestByUnique(unique: string): Promise<UmbRepositoryResponseWithAsObservable<DetailModelType>>;
byUnique(unique: string): Promise<Observable<DetailModelType | undefined>>;
create(data: DetailModelType, parentUnique: string | null): Promise<UmbRepositoryResponse<DetailModelType>>;
save(data: DetailModelType): Promise<UmbRepositoryResponse<DetailModelType>>;
delete(unique: string): Promise<UmbRepositoryErrorResponse>;

View File

@@ -1,3 +1,11 @@
// Read
export type {
UmbReadDetailDataSource,
UmbReadDetailDataSourceConstructor,
} from './read/read-detail-data-source.interface.js';
export type { UmbReadDetailRepository } from './read/read-detail-repository.interface.js';
// Combined
export type { UmbDetailDataSource, UmbDetailDataSourceConstructor } from './detail-data-source.interface.js';
export { UmbDetailRepositoryBase } from './detail-repository-base.js';
export type { UmbDetailRepository } from './detail-repository.interface.js';

View File

@@ -0,0 +1,5 @@
export type {
UmbReadDetailDataSource,
UmbReadDetailDataSourceConstructor,
} from './read-detail-data-source.interface.js';
export type { UmbReadDetailRepository } from './read-detail-repository.interface.js';

View File

@@ -0,0 +1,10 @@
import type { UmbDataSourceResponse } from '../../data-source-response.interface.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
export interface UmbReadDetailDataSourceConstructor<DetailType = any> {
new (host: UmbControllerHost): UmbReadDetailDataSource<DetailType>;
}
export interface UmbReadDetailDataSource<DetailType> {
read(unique: string): Promise<UmbDataSourceResponse<DetailType>>;
}

View File

@@ -0,0 +1,8 @@
import type { UmbRepositoryResponseWithAsObservable } from '../../types.js';
import type { UmbApi } from '@umbraco-cms/backoffice/extension-api';
import type { Observable } from '@umbraco-cms/backoffice/external/rxjs';
export interface UmbReadDetailRepository<DetailModelType> extends UmbApi {
requestByUnique(unique: string): Promise<UmbRepositoryResponseWithAsObservable<DetailModelType>>;
byUnique(unique: string): Promise<Observable<DetailModelType | undefined>>;
}

View File

@@ -1,38 +1,54 @@
import { UmbTemporaryFileRepository } from './temporary-file.repository.js';
import { UmbArrayState, UmbBooleanState } from '@umbraco-cms/backoffice/observable-api';
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import { UmbId } from '@umbraco-cms/backoffice/id';
export type TemporaryFileStatus = 'complete' | 'waiting' | 'error';
export type TemporaryFileStatus = 'success' | 'waiting' | 'error';
export interface TemporaryFileQueueItem {
unique: string;
export interface UmbTemporaryFileModel {
file: File;
unique: string;
status: TemporaryFileStatus;
}
export interface UmbTemporaryFileQueueModel extends Partial<UmbTemporaryFileModel> {
file: File;
status?: TemporaryFileStatus;
}
export class UmbTemporaryFileManager extends UmbControllerBase {
#temporaryFileRepository;
#queue = new UmbArrayState<TemporaryFileQueueItem>([], (item) => item.unique);
#queue = new UmbArrayState<UmbTemporaryFileModel>([], (item) => item.unique);
public readonly queue = this.#queue.asObservable();
#isReady = new UmbBooleanState(true);
public readonly isReady = this.#isReady.asObservable();
constructor(host: UmbControllerHost) {
super(host);
this.#temporaryFileRepository = new UmbTemporaryFileRepository(host);
}
uploadOne(unique: string, file: File, status: TemporaryFileStatus = 'waiting') {
this.#queue.appendOne({ unique, file, status });
this.handleQueue();
async uploadOne(queueItem: UmbTemporaryFileQueueModel): Promise<Array<UmbTemporaryFileModel>> {
this.#queue.setValue([]);
const item: UmbTemporaryFileModel = {
file: queueItem.file,
unique: queueItem.unique ?? UmbId.new(),
status: queueItem.status ?? 'waiting',
};
this.#queue.appendOne(item);
return this.handleQueue();
}
upload(queueItems: Array<TemporaryFileQueueItem>) {
this.#queue.append(queueItems);
this.handleQueue();
async upload(queueItems: Array<UmbTemporaryFileQueueModel>): Promise<Array<UmbTemporaryFileModel>> {
this.#queue.setValue([]);
const items = queueItems.map(
(item): UmbTemporaryFileModel => ({
file: item.file,
unique: item.unique ?? UmbId.new(),
status: item.status ?? 'waiting',
}),
);
this.#queue.append(items);
return this.handleQueue();
}
removeOne(unique: string) {
@@ -44,31 +60,29 @@ export class UmbTemporaryFileManager extends UmbControllerBase {
}
private async handleQueue() {
const filesCompleted: Array<UmbTemporaryFileModel> = [];
const queue = this.#queue.getValue();
if (!queue.length && this.getIsReady()) return;
if (!queue.length) return filesCompleted;
this.#isReady.setValue(false);
queue.forEach(async (item) => {
if (item.status !== 'waiting') return;
for (const item of queue) {
if (!item.unique) throw new Error(`Unique is missing for item ${item}`);
const { error } = await this.#temporaryFileRepository.upload(item.unique, item.file);
await new Promise((resolve) => setTimeout(resolve, (Math.random() + 0.5) * 1000)); // simulate small delay so that the upload badge is properly shown
let status: TemporaryFileStatus;
if (error) {
this.#queue.updateOne(item.unique, { ...item, status: 'error' });
status = 'error';
this.#queue.updateOne(item.unique, { ...item, status });
} else {
this.#queue.updateOne(item.unique, { ...item, status: 'complete' });
status = 'success';
this.#queue.updateOne(item.unique, { ...item, status });
}
});
if (!queue.find((item) => item.status === 'waiting') && !this.getIsReady()) {
this.#isReady.setValue(true);
filesCompleted.push({ ...item, status });
}
}
getIsReady() {
return this.#queue.getValue();
return filesCompleted;
}
}

View File

@@ -1,9 +1,11 @@
import { manifests as workspaceActionManifests } from './workspace-action/manifests.js';
import { manifests as workspaceActionMenuItemManifests } from './workspace-action-menu-item/manifests.js';
import { manifests as workspaceBreadcrumbManifests } from './workspace-breadcrumb/manifests.js';
import { manifests as workspaceViewManifests } from './workspace-collection/manifests.js';
export const manifests = [
...workspaceActionManifests,
...workspaceActionMenuItemManifests,
...workspaceBreadcrumbManifests,
...workspaceViewManifests,
];

View File

@@ -0,0 +1,25 @@
import type { ManifestWorkspaceView } from '@umbraco-cms/backoffice/extension-registry';
export const manifests: Array<ManifestWorkspaceView> = [
{
type: 'workspaceView',
alias: 'Umb.WorkspaceView.Collection',
name: 'Workspace Collection View',
element: () => import('./workspace-view-collection.element.js'),
weight: 300,
meta: {
label: 'Collection',
pathname: 'collection',
icon: 'icon-grid',
},
conditions: [
{
alias: 'Umb.Condition.WorkspaceAlias',
oneOf: ['Umb.Workspace.Document', 'Umb.Workspace.Media'],
},
{
alias: 'Umb.Condition.WorkspaceHasCollection',
},
],
},
];

View File

@@ -1,20 +1,23 @@
import type {
UmbCollectionBulkActionPermissions,
UmbCollectionConfiguration,
} from '../../../../../core/collection/types.js';
import type { UmbCollectionBulkActionPermissions, UmbCollectionConfiguration } from '../../../collection/types.js';
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';
import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/document';
import { UMB_COLLECTION_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
import type { UmbDataTypeDetailModel } from '@umbraco-cms/backoffice/data-type';
import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry';
@customElement('umb-document-workspace-view-collection')
export class UmbDocumentWorkspaceViewCollectionElement extends UmbLitElement implements UmbWorkspaceViewElement {
@customElement('umb-workspace-view-collection')
export class UmbWorkspaceViewCollectionElement extends UmbLitElement implements UmbWorkspaceViewElement {
@state()
private _loading = true;
@state()
private _config?: UmbCollectionConfiguration;
@state()
private _collectionAlias?: string;
@state()
private _documentUnique?: string;
@@ -26,16 +29,16 @@ export class UmbDocumentWorkspaceViewCollectionElement extends UmbLitElement imp
}
async #observeConfig() {
this.consumeContext(UMB_DOCUMENT_WORKSPACE_CONTEXT, (workspaceContext) => {
this.observe(workspaceContext.unique, (unique) => {
this._documentUnique = unique;
});
this.consumeContext(UMB_COLLECTION_WORKSPACE_CONTEXT, (workspaceContext) => {
this._collectionAlias = workspaceContext.getCollectionAlias();
this._documentUnique = workspaceContext.getUnique() ?? '';
this.observe(
workspaceContext.structure.ownerContentType,
async (documentType) => {
if (!documentType || !documentType.collection) return;
async (contentType) => {
if (!contentType || !contentType.collection) return;
const dataTypeUnique = documentType.collection.unique;
const dataTypeUnique = contentType.collection.unique;
if (dataTypeUnique) {
await this.#dataTypeDetailRepository.requestByUnique(dataTypeUnique);
@@ -44,12 +47,13 @@ export class UmbDocumentWorkspaceViewCollectionElement extends UmbLitElement imp
(dataType) => {
if (!dataType) return;
this._config = this.#mapDataTypeConfigToCollectionConfig(dataType);
this._loading = false;
},
'_observeConfigDataType',
);
}
},
'_observeConfigDocumentType',
'_observeConfigContentType',
);
});
}
@@ -59,6 +63,7 @@ export class UmbDocumentWorkspaceViewCollectionElement extends UmbLitElement imp
return {
unique: this._documentUnique,
allowedEntityBulkActions: config?.getValueByAlias<UmbCollectionBulkActionPermissions>('bulkActionPermissions'),
layouts: config?.getValueByAlias('layouts'),
orderBy: config?.getValueByAlias('orderBy') ?? 'updateDate',
orderDirection: config?.getValueByAlias('orderDirection') ?? 'asc',
pageSize: Number(config?.getValueByAlias('pageSize')) ?? 50,
@@ -68,15 +73,15 @@ export class UmbDocumentWorkspaceViewCollectionElement extends UmbLitElement imp
}
render() {
if (!this._config?.unique) return nothing;
return html`<umb-collection alias="Umb.Collection.Document" .config=${this._config}></umb-collection>`;
if (this._loading) return nothing;
return html`<umb-collection .alias=${this._collectionAlias} .config=${this._config}></umb-collection>`;
}
}
export default UmbDocumentWorkspaceViewCollectionElement;
export default UmbWorkspaceViewCollectionElement;
declare global {
interface HTMLElementTagNameMap {
'umb-document-workspace-view-collection': UmbDocumentWorkspaceViewCollectionElement;
'umb-workspace-view-collection': UmbWorkspaceViewCollectionElement;
}
}

View File

@@ -3,5 +3,7 @@ export * from './contexts/index.js';
export * from './controllers/index.js';
export * from './modals/index.js';
export * from './workspace-property-dataset/index.js';
export * from './workspace.element.js';
export type * from './conditions/index.js';
export type * from './types.js';

View File

@@ -203,11 +203,6 @@ export class UmbDocumentTableCollectionViewElement extends UmbLitElement {
padding: var(--uui-size-space-3) 0;
}
/* TODO: Should we have embedded padding in the table component? */
umb-table {
padding: 0; /* To fix the embedded padding in the table component. */
}
.container {
display: flex;
justify-content: center;

View File

@@ -1,7 +1,7 @@
import './components/index.js';
export * from './repository/index.js';
export * from './tracked-reference/index.js';
export * from './reference/index.js';
export * from './workspace/index.js';
export * from './recycle-bin/index.js';
export * from './user-permissions/index.js';

View File

@@ -6,7 +6,7 @@ import { manifests as menuManifests } from './menu/manifests.js';
import { manifests as propertyEditorManifests } from './property-editors/manifests.js';
import { manifests as recycleBinManifests } from './recycle-bin/manifests.js';
import { manifests as repositoryManifests } from './repository/manifests.js';
import { manifests as trackedReferenceManifests } from './tracked-reference/manifests.js';
import { manifests as trackedReferenceManifests } from './reference/manifests.js';
import { manifests as treeManifests } from './tree/manifests.js';
import { manifests as userPermissionManifests } from './user-permissions/manifests.js';
import { manifests as workspaceManifests } from './workspace/manifests.js';

View File

@@ -1,5 +1,5 @@
import { UmbDocumentVariantState, type UmbDocumentVariantOptionModel } from '../../types.js';
import { UmbDocumentTrackedReferenceRepository } from '../../tracked-reference/index.js';
import { UmbDocumentReferenceRepository } from '../../reference/index.js';
import { UMB_DOCUMENT_CONFIGURATION_CONTEXT } from '../../global-contexts/index.js';
import type {
UmbDocumentUnpublishModalData,
@@ -18,20 +18,20 @@ export class UmbDocumentUnpublishModalElement extends UmbModalBaseElement<
UmbDocumentUnpublishModalValue
> {
#selectionManager = new UmbSelectionManager<string>(this);
#trackedReferencesRepository = new UmbDocumentTrackedReferenceRepository(this);
#referencesRepository = new UmbDocumentReferenceRepository(this);
@state()
_options: Array<UmbDocumentVariantOptionModel> = [];
@state()
_hasTrackedReferences = false;
_hasReferences = false;
@state()
_hasUnpublishPermission = true;
firstUpdated() {
this.#configureSelectionManager();
this.#getTrackedReferences();
this.#getReferences();
}
async #configureSelectionManager() {
@@ -56,14 +56,10 @@ export class UmbDocumentUnpublishModalElement extends UmbModalBaseElement<
this.#selectionManager.setSelection(selected);
}
async #getTrackedReferences() {
async #getReferences() {
if (!this.data?.documentUnique) return;
const { data, error } = await this.#trackedReferencesRepository.requestTrackedReference(
this.data?.documentUnique,
0,
1,
);
const { data, error } = await this.#referencesRepository.requestReferencedBy(this.data?.documentUnique, 0, 1);
if (error) {
console.error(error);
@@ -72,10 +68,10 @@ export class UmbDocumentUnpublishModalElement extends UmbModalBaseElement<
if (!data) return;
this._hasTrackedReferences = data.total > 0;
this._hasReferences = data.total > 0;
// If there are tracked references, we also want to check if we are allowed to unpublish the document:
if (this._hasTrackedReferences) {
// If there are references, we also want to check if we are allowed to unpublish the document:
if (this._hasReferences) {
const documentConfigurationContext = await this.getContext(UMB_DOCUMENT_CONFIGURATION_CONTEXT);
this._hasUnpublishPermission =
(await documentConfigurationContext.getDocumentConfiguration())?.disableUnpublishWhenReferenced === false;
@@ -115,13 +111,13 @@ export class UmbDocumentUnpublishModalElement extends UmbModalBaseElement<
${this.data?.documentUnique
? html`
<umb-document-tracked-reference-table
id="tracked-references"
unique=${this.data?.documentUnique}></umb-document-tracked-reference-table>
<umb-document-reference-table
id="references"
unique=${this.data?.documentUnique}></umb-document-reference-table>
`
: nothing}
${this._hasTrackedReferences
? html`<uui-box id="tracked-references-warning">
${this._hasReferences
? html`<uui-box id="references-warning">
<umb-localize key="references_unpublishWarning">
This item or its descendants is being referenced. Unpublishing can lead to broken links on your website.
Please take the appropriate actions.
@@ -150,11 +146,11 @@ export class UmbDocumentUnpublishModalElement extends UmbModalBaseElement<
max-width: 90vw;
}
#tracked-references {
#references {
--uui-table-cell-padding: 0;
}
#tracked-references-warning {
#references-warning {
margin-top: 1rem;
background-color: var(--uui-color-danger);
color: var(--uui-color-danger-contrast);

View File

@@ -1,19 +1,24 @@
import { UmbDocumentTrackedReferenceRepository } from '../repository/index.js';
import type { RelationItemResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
import { UmbDocumentReferenceRepository } from '../repository/index.js';
import { css, customElement, html, nothing, property, repeat, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import {
type UmbReferenceModel,
isDocumentReference,
isMediaReference,
isDefaultReference,
} from '@umbraco-cms/backoffice/relations';
@customElement('umb-document-tracked-reference-table')
export class UmbDocumentTrackedReferenceTableElement extends UmbLitElement {
#documentTrackedReferenceRepository = new UmbDocumentTrackedReferenceRepository(this);
@customElement('umb-document-reference-table')
export class UmbDocumentReferenceTableElement extends UmbLitElement {
#documentReferenceRepository = new UmbDocumentReferenceRepository(this);
#pageSize = 10;
@property()
unique = '';
@state()
_items: Array<RelationItemResponseModel> = [];
_items: Array<UmbReferenceModel> = [];
/**
* Indicates if there are more references to load, i.e. if the server has more references to return.
@@ -26,16 +31,12 @@ export class UmbDocumentTrackedReferenceTableElement extends UmbLitElement {
_errorMessage = '';
firstUpdated() {
this.#getTrackedReferences();
this.#getReferences();
}
async #getTrackedReferences() {
// Get the first 10 tracked references for the document:
const { data, error } = await this.#documentTrackedReferenceRepository.requestTrackedReference(
this.unique,
0,
this.#pageSize,
);
async #getReferences() {
// Get the first 10 references for the document:
const { data, error } = await this.#documentReferenceRepository.requestReferencedBy(this.unique, 0, this.#pageSize);
if (error) {
this._errorMessage = error.message;
@@ -52,6 +53,32 @@ export class UmbDocumentTrackedReferenceTableElement extends UmbLitElement {
return html` ${this.#renderErrorMessage()} ${this.#renderTable()} `;
}
#getIcon(item: UmbReferenceModel) {
if (isDocumentReference(item)) {
return item.documentType.icon ?? 'icon-document';
}
if (isMediaReference(item)) {
return item.mediaType.icon ?? 'icon-picture';
}
if (isDefaultReference(item)) {
return item.icon ?? 'icon-document';
}
return 'icon-document';
}
#getContentTypeName(item: UmbReferenceModel) {
if (isDocumentReference(item)) {
return item.documentType.name;
}
if (isMediaReference(item)) {
return item.mediaType.name;
}
if (isDefaultReference(item)) {
return item.type;
}
return '';
}
#renderTable() {
if (this._items?.length === 0) return nothing;
return html`
@@ -65,14 +92,14 @@ export class UmbDocumentTrackedReferenceTableElement extends UmbLitElement {
${repeat(
this._items,
(item) => item.nodeId,
(item) => item.id,
(item) =>
html`<uui-table-row>
<uui-table-cell style="text-align:center; vertical-align:revert;">
<umb-icon name=${item.contentTypeIcon ?? 'icon-document'}></umb-icon>
<uui-table-cell style="text-align:center;">
<umb-icon name=${this.#getIcon(item)}></umb-icon>
</uui-table-cell>
<uui-table-cell class="link-cell"> ${item.nodeName} </uui-table-cell>
<uui-table-cell>${item.contentTypeName}</uui-table-cell>
<uui-table-cell class="link-cell"> ${item.name} </uui-table-cell>
<uui-table-cell>${this.#getContentTypeName(item)}</uui-table-cell>
</uui-table-row>`,
)}
${this._hasMoreReferences
@@ -111,6 +138,6 @@ export class UmbDocumentTrackedReferenceTableElement extends UmbLitElement {
declare global {
interface HTMLElementTagNameMap {
'umb-document-tracked-reference-table': UmbDocumentTrackedReferenceTableElement;
'umb-document-reference-table': UmbDocumentReferenceTableElement;
}
}

View File

@@ -0,0 +1,51 @@
import type { Meta, StoryObj } from '@storybook/web-components';
import type { UmbDocumentReferenceTableElement } from './document-reference-table.element.js';
import { html } from '@umbraco-cms/backoffice/external/lit';
import './document-reference-table.element.js';
const meta: Meta<UmbDocumentReferenceTableElement> = {
id: 'umb-document-reference-table',
title: 'Components/Document/Reference Table',
component: 'umb-document-reference-table',
args: {
unique: '1234',
},
parameters: {
actions: {
disabled: true,
},
docs: {
source: {
language: 'html',
code: `
<umb-document-reference-table unique="<Content GUID>"></umb-document-reference-table>
`,
},
},
},
};
export default meta;
type Story = StoryObj<UmbDocumentReferenceTableElement>;
export const Overview: Story = {};
export const SlimTable: Story = {
decorators: [
(story) => {
return html`<div style="--uui-table-cell-padding: 0;">${story()}</div>`;
},
],
parameters: {
docs: {
source: {
language: 'html',
code: `
<umb-document-reference-table unique="<Content GUID>" style="--uui-table-cell-padding:0"></umb-document-reference-table>
`,
},
},
},
};

View File

@@ -0,0 +1 @@
export * from './document-reference-table.element.js';

View File

@@ -1,3 +1,2 @@
//export * from './manifests.js';
export * from './components/index.js';
export * from './repository/index.js';

View File

@@ -1,5 +1,3 @@
import { manifests as repositoryManifests } from './repository/manifests.js';
export const UMB_TRACKED_REFERENCE_MEDIA = 'Umb.TrackedReference.Media';
export const manifests = [...repositoryManifests];

View File

@@ -0,0 +1,19 @@
import { UmbDocumentReferenceServerDataSource } from './document-reference.server.data.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
export class UmbDocumentReferenceRepository extends UmbControllerBase {
#referenceSource: UmbDocumentReferenceServerDataSource;
constructor(host: UmbControllerHost) {
super(host);
this.#referenceSource = new UmbDocumentReferenceServerDataSource(this);
}
async requestReferencedBy(unique: string, skip = 0, take = 20) {
if (!unique) throw new Error(`unique is required`);
return this.#referenceSource.getReferencedBy(unique, skip, take);
}
}
export default UmbDocumentReferenceRepository;

View File

@@ -0,0 +1,31 @@
import { DocumentResource } from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**
* @export
* @class UmbDocumentReferenceServerDataSource
* @implements {RepositoryDetailDataSource}
*/
export class UmbDocumentReferenceServerDataSource {
#host: UmbControllerHost;
/**
* Creates an instance of UmbDocumentReferenceServerDataSource.
* @param {UmbControllerHost} host
* @memberof UmbDocumentReferenceServerDataSource
*/
constructor(host: UmbControllerHost) {
this.#host = host;
}
/**
* Fetches the item for the given unique from the server
* @param {string} id
* @return {*}
* @memberof UmbDocumentReferenceServerDataSource
*/
async getReferencedBy(id: string, skip = 0, take = 20) {
return await tryExecuteAndNotify(this.#host, DocumentResource.getDocumentByIdReferencedBy({ id, skip, take }));
}
}

View File

@@ -0,0 +1 @@
export * from './document-reference.repository.js';

View File

@@ -0,0 +1,12 @@
import type { ManifestRepository } from '@umbraco-cms/backoffice/extension-registry';
export const UMB_DOCUMENT_REFERENCE_REPOSITORY_ALIAS = 'Umb.Repository.Document.Reference';
const repository: ManifestRepository = {
type: 'repository',
alias: UMB_DOCUMENT_REFERENCE_REPOSITORY_ALIAS,
name: 'Document Reference Repository',
api: () => import('./document-reference.repository.js'),
};
export const manifests = [repository];

View File

@@ -1,51 +0,0 @@
import type { Meta, StoryObj } from '@storybook/web-components';
import type { UmbDocumentTrackedReferenceTableElement } from './document-tracked-reference-table.element.js';
import { html } from '@umbraco-cms/backoffice/external/lit';
import './document-tracked-reference-table.element.js';
const meta: Meta<UmbDocumentTrackedReferenceTableElement> = {
id: 'umb-document-tracked-reference-table',
title: 'Components/Document/Tracked Reference Table',
component: 'umb-document-tracked-reference-table',
args: {
unique: '1234',
},
parameters: {
actions: {
disabled: true,
},
docs: {
source: {
language: 'html',
code: `
<umb-document-tracked-reference-table unique="<Content GUID>"></umb-document-tracked-reference-table>
`,
},
},
},
};
export default meta;
type Story = StoryObj<UmbDocumentTrackedReferenceTableElement>;
export const Overview: Story = {};
export const SlimTable: Story = {
decorators: [
(story) => {
return html`<div style="--uui-table-cell-padding: 0;">${story()}</div>`;
},
],
parameters: {
docs: {
source: {
language: 'html',
code: `
<umb-document-tracked-reference-table unique="<Content GUID>" style="--uui-table-cell-padding:0"></umb-document-tracked-reference-table>
`,
},
},
},
};

View File

@@ -1 +0,0 @@
export * from './document-tracked-reference-table.element.js';

View File

@@ -1,39 +0,0 @@
import { UmbDocumentTrackedReferenceServerDataSource } from './document-tracked-reference.server.data.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
export class UmbDocumentTrackedReferenceRepository extends UmbControllerBase {
#trackedReferenceSource: UmbDocumentTrackedReferenceServerDataSource;
constructor(host: UmbControllerHost) {
super(host);
this.#trackedReferenceSource = new UmbDocumentTrackedReferenceServerDataSource(this);
}
async requestTrackedReference(unique: string, skip = 0, take = 20, filterMustBeIsDependency = false) {
if (!unique) throw new Error(`unique is required`);
return this.#trackedReferenceSource.getTrackedReferenceById(unique, skip, take, filterMustBeIsDependency);
}
async requestTrackedReferenceDescendantsFromParentUnique(
parentUnique: string,
skip = 0,
take = 20,
filterMustBeIsDependency = false,
) {
if (!parentUnique) throw new Error(`unique is required`);
return this.#trackedReferenceSource.getTrackedReferenceDescendantsByParentId(
parentUnique,
skip,
take,
filterMustBeIsDependency,
);
}
async requestTrackedReferenceItems(uniques: string[], skip = 0, take = 20, filterMustBeIsDependency = true) {
if (!uniques) throw new Error(`unique is required`);
return this.#trackedReferenceSource.getTrackedReferenceItem(uniques, skip, take, filterMustBeIsDependency);
}
}
export default UmbDocumentTrackedReferenceRepository;

View File

@@ -1,75 +0,0 @@
import { TrackedReferenceResource } from '@umbraco-cms/backoffice/external/backend-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
/**
* @export
* @class UmbUserGroupCollectionServerDataSource
* @implements {RepositoryDetailDataSource}
*/
export class UmbDocumentTrackedReferenceServerDataSource {
#host: UmbControllerHost;
/**
* Creates an instance of UmbDocumentTrackedReferenceServerDataSource.
* @param {UmbControllerHost} host
* @memberof UmbDocumentTrackedReferenceServerDataSource
*/
constructor(host: UmbControllerHost) {
this.#host = host;
}
/**
* Fetches the item for the given id from the server
* @param {Array<string>} ids
* @return {*}
* @memberof UmbDataTypeItemServerDataSource
*/
async getTrackedReferenceById(id: string, skip = 0, take = 20, filterMustBeIsDependency = false) {
return await tryExecuteAndNotify(
this.#host,
TrackedReferenceResource.getTrackedReferenceById({ id, skip, take, filterMustBeIsDependency }),
);
}
/**
* Fetches the item descendant for the given id from the server
* @param {Array<string>} ids
* @return {*}
* @memberof UmbDocumentTrackedReferenceServerDataSource
*/
async getTrackedReferenceDescendantsByParentId(
parentId: string,
skip = 0,
take = 20,
filterMustBeIsDependency = false,
) {
return await tryExecuteAndNotify(
this.#host,
TrackedReferenceResource.getTrackedReferenceDescendantsByParentId({
parentId,
skip,
take,
filterMustBeIsDependency,
}),
);
}
/**
* Fetches the items for the given ids from the server
* @param {Array<string>} ids
* @return {*}
* @memberof UmbDocumentTrackedReferenceServerDataSource
*/
async getTrackedReferenceItem(id: string[], skip = 0, take = 20, filterMustBeIsDependency = true) {
return await tryExecuteAndNotify(
this.#host,
TrackedReferenceResource.getTrackedReferenceItem({
id,
skip,
take,
filterMustBeIsDependency,
}),
);
}
}

View File

@@ -1 +0,0 @@
export * from './document-tracked-reference.repository.js';

View File

@@ -1,12 +0,0 @@
import type { ManifestRepository } from '@umbraco-cms/backoffice/extension-registry';
export const UMB_DOCUMENT_TRACKED_REFERENCE_REPOSITORY_ALIAS = 'Umb.Repository.Document.TrackedReference';
const repository: ManifestRepository = {
type: 'repository',
alias: UMB_DOCUMENT_TRACKED_REFERENCE_REPOSITORY_ALIAS,
name: 'Document Tracked Reference Repository',
api: () => import('./document-tracked-reference.repository.js'),
};
export const manifests = [repository];

View File

@@ -98,8 +98,14 @@ export class UmbDocumentWorkspaceEditorElement extends UmbLitElement {
routes.push({
path: '',
resolve: () => {
// Retrieve the current app language variant id from the context and redirect to the correct route.
history.pushState({}, '', `${this.#workspaceRoute}/${this.#appCulture}/${this.#variants![0].unique}`);
const route = routes.find((route) => route.path === this.#appCulture);
if (!route) {
history.pushState({}, '', `${this.#workspaceRoute}/${routes[routes.length - 2].path}`);
return;
}
history.pushState({}, '', `${this.#workspaceRoute}/${route?.path}`);
},
});
}

View File

@@ -25,27 +25,6 @@ const workspace: ManifestWorkspaces = {
};
const workspaceViews: Array<ManifestWorkspaceView> = [
{
type: 'workspaceView',
alias: 'Umb.WorkspaceView.Document.Collection',
name: 'Document Workspace Collection View',
element: () => import('./views/collection/document-workspace-view-collection.element.js'),
weight: 300,
meta: {
label: 'Documents',
pathname: 'collection',
icon: 'icon-grid',
},
conditions: [
{
alias: 'Umb.Condition.WorkspaceAlias',
match: workspace.alias,
},
{
alias: 'Umb.Condition.WorkspaceHasCollection',
},
],
},
{
type: 'workspaceView',
alias: 'Umb.WorkspaceView.Document.Edit',

View File

@@ -1,15 +1,20 @@
import { UmbDocumentReferenceRepository } from '../../../reference/index.js';
import { css, html, customElement, state, nothing, repeat, property } from '@umbraco-cms/backoffice/external/lit';
import type { UUIPaginationEvent } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { RelationItemResponseModel } from '@umbraco-cms/backoffice/external/backend-api';
import { UmbDocumentTrackedReferenceRepository } from '@umbraco-cms/backoffice/document';
import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal';
import {
isDefaultReference,
isDocumentReference,
isMediaReference,
type UmbReferenceModel,
} from '@umbraco-cms/backoffice/relations';
@customElement('umb-document-workspace-view-info-reference')
export class UmbDocumentWorkspaceViewInfoReferenceElement extends UmbLitElement {
#itemsPerPage = 10;
#trackedReferenceRepository;
#referenceRepository;
@property()
documentUnique = '';
@@ -24,11 +29,11 @@ export class UmbDocumentWorkspaceViewInfoReferenceElement extends UmbLitElement
private _total = 0;
@state()
private _items?: Array<RelationItemResponseModel> = [];
private _items?: Array<UmbReferenceModel> = [];
constructor() {
super();
this.#trackedReferenceRepository = new UmbDocumentTrackedReferenceRepository(this);
this.#referenceRepository = new UmbDocumentReferenceRepository(this);
new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL)
.addAdditionalPath('document')
@@ -45,7 +50,7 @@ export class UmbDocumentWorkspaceViewInfoReferenceElement extends UmbLitElement
}
async #getReferences() {
const { data } = await this.#trackedReferenceRepository.requestTrackedReference(
const { data } = await this.#referenceRepository.requestReferencedBy(
this.documentUnique,
(this._currentPage - 1) * this.#itemsPerPage,
this.#itemsPerPage,
@@ -63,6 +68,49 @@ export class UmbDocumentWorkspaceViewInfoReferenceElement extends UmbLitElement
this.#getReferences();
}
#getIcon(item: UmbReferenceModel) {
if (isDocumentReference(item)) {
return item.documentType.icon ?? 'icon-document';
}
if (isMediaReference(item)) {
return item.mediaType.icon ?? 'icon-picture';
}
if (isDefaultReference(item)) {
return item.icon ?? 'icon-document';
}
return 'icon-document';
}
#getPublishedStatus(item: UmbReferenceModel) {
return isDocumentReference(item) ? item.published : true;
}
#getContentTypeName(item: UmbReferenceModel) {
if (isDocumentReference(item)) {
return item.documentType.name;
}
if (isMediaReference(item)) {
return item.mediaType.name;
}
if (isDefaultReference(item)) {
return item.type;
}
return '';
}
#getContentType(item: UmbReferenceModel) {
if (isDocumentReference(item)) {
return item.documentType.alias;
}
if (isMediaReference(item)) {
return item.mediaType.alias;
}
if (isDefaultReference(item)) {
return item.type;
}
return '';
}
render() {
if (this._items && this._items.length > 0) {
return html` <uui-box
@@ -75,32 +123,32 @@ export class UmbDocumentWorkspaceViewInfoReferenceElement extends UmbLitElement
<uui-table-head-cell><umb-localize key="general_status">Status</umb-localize></uui-table-head-cell>
<uui-table-head-cell><umb-localize key="general_typeName">Type Name</umb-localize></uui-table-head-cell>
<uui-table-head-cell><umb-localize key="general_type">Type</umb-localize></uui-table-head-cell>
<uui-table-head-cell>
<umb-localize key="relationType_relation">Relation</umb-localize>
</uui-table-head-cell>
</uui-table-head>
${repeat(
this._items,
(item) => item.nodeId,
(item) => item.id,
(item) =>
html`<uui-table-row>
<uui-table-cell style="text-align:center;">
<umb-icon name=${item.contentTypeIcon ?? 'icon-document'}></umb-icon>
<umb-icon name=${this.#getIcon(item)}></umb-icon>
</uui-table-cell>
<uui-table-cell class="link-cell">
<uui-button label="Edit" href=${`${this._editDocumentPath}edit/${item.nodeId}`}>
${item.nodeName}
</uui-button>
${isDocumentReference(item)
? html` <uui-button
label="${this.localize.term('general_edit')} ${item.name}"
href=${`${this._editDocumentPath}edit/${item.id}`}>
${item.name}
</uui-button>`
: item.name}
</uui-table-cell>
<uui-table-cell>
${item.nodePublished
${this.#getPublishedStatus(item)
? this.localize.term('content_published')
: this.localize.term('content_unpublished')}
</uui-table-cell>
<uui-table-cell>${item.contentTypeName}</uui-table-cell>
<uui-table-cell>${item.nodeType}</uui-table-cell>
<uui-table-cell>${item.relationTypeName}</uui-table-cell>
<uui-table-cell>${this.#getContentTypeName(item)}</uui-table-cell>
<uui-table-cell>${this.#getContentType(item)}</uui-table-cell>
</uui-table-row>`,
)}
</uui-table>
@@ -126,10 +174,6 @@ export class UmbDocumentWorkspaceViewInfoReferenceElement extends UmbLitElement
static styles = [
UmbTextStyles,
css`
.link-cell {
font-weight: bold;
}
uui-table-cell:not(.link-cell) {
color: var(--uui-color-text-alt);
}

View File

@@ -6,3 +6,5 @@ export * from './workspace/index.js';
export * from './repository/index.js';
export * from './tree/types.js';
export * from './types.js';
export * from './utils/index.js';

View File

@@ -0,0 +1,28 @@
export enum UmbMediaTypeFileType {
SVG = 'Vector Graphics (SVG)',
IMAGE = 'Image',
AUDIO = 'Audio',
VIDEO = 'Video',
ARTICLE = 'Article',
FILE = 'File',
}
export function getMediaTypeByFileExtension(extension: string) {
if (extension === 'svg') return UmbMediaTypeFileType.SVG;
if (['jpg', 'jpeg', 'gif', 'bmp', 'png', 'tiff', 'tif', 'webp'].includes(extension))
return UmbMediaTypeFileType.IMAGE;
if (['mp3', 'weba', 'oga', 'opus'].includes(extension)) return UmbMediaTypeFileType.AUDIO;
if (['mp4', 'webm', 'ogv'].includes(extension)) return UmbMediaTypeFileType.VIDEO;
if (['pdf', 'docx', 'doc'].includes(extension)) return UmbMediaTypeFileType.ARTICLE;
return UmbMediaTypeFileType.FILE;
}
export function getMediaTypeByFileMimeType(mimetype: string) {
if (mimetype === 'image/svg+xml') return UmbMediaTypeFileType.SVG;
const [type, extension] = mimetype.split('/');
if (type === 'image') return UmbMediaTypeFileType.IMAGE;
if (type === 'audio') return UmbMediaTypeFileType.AUDIO;
if (type === 'video') return UmbMediaTypeFileType.VIDEO;
if (['pdf', 'docx', 'doc'].includes(extension)) return UmbMediaTypeFileType.ARTICLE;
return UmbMediaTypeFileType.FILE;
}

View File

@@ -1,87 +1,40 @@
import { css, customElement, html } from '@umbraco-cms/backoffice/external/lit';
import { UmbCollectionDefaultElement } from '@umbraco-cms/backoffice/collection';
import type { UmbMediaCollectionContext } from './media-collection.context.js';
import { customElement, html, state, when } from '@umbraco-cms/backoffice/external/lit';
import { UMB_DEFAULT_COLLECTION_CONTEXT, UmbCollectionDefaultElement } from '@umbraco-cms/backoffice/collection';
import type { UmbProgressEvent } from '@umbraco-cms/backoffice/event';
import './media-collection-toolbar.element.js';
@customElement('umb-media-collection')
export class UmbMediaCollectionElement extends UmbCollectionDefaultElement {
#mediaCollection?: UmbMediaCollectionContext;
@state()
private _progress = -1;
constructor() {
super();
document.addEventListener('dragenter', this.#handleDragEnter.bind(this));
document.addEventListener('dragleave', this.#handleDragLeave.bind(this));
document.addEventListener('drop', this.#handleDrop.bind(this));
this.consumeContext(UMB_DEFAULT_COLLECTION_CONTEXT, (instance) => {
this.#mediaCollection = instance as UmbMediaCollectionContext;
});
}
disconnectedCallback(): void {
super.disconnectedCallback();
document.removeEventListener('dragenter', this.#handleDragEnter.bind(this));
document.removeEventListener('dragleave', this.#handleDragLeave.bind(this));
document.removeEventListener('drop', this.#handleDrop.bind(this));
#onChange() {
this._progress = -1;
this.#mediaCollection?.requestCollection();
}
#handleDragEnter() {
this.toggleAttribute('dragging', true);
}
#handleDragLeave() {
this.toggleAttribute('dragging', false);
}
#handleDrop(event: DragEvent) {
event.preventDefault();
console.log('#handleDrop', event);
this.toggleAttribute('dragging', false);
}
#onFileChange(event: Event) {
console.log('#onFileChange', event);
#onProgress(event: UmbProgressEvent) {
this._progress = event.progress;
}
protected renderToolbar() {
return html`
<umb-media-collection-toolbar slot="header"></umb-media-collection-toolbar>
<!-- TODO: Add the Media Upload dropzone component in here. [LK] -->
<uui-file-dropzone
id="dropzone"
multiple
@file-change=${this.#onFileChange}
label="${this.localize.term('media_dragAndDropYourFilesIntoTheArea')}"
accept=""></uui-file-dropzone>
${when(this._progress >= 0, () => html`<uui-loader-bar progress=${this._progress}></uui-loader-bar>`)}
<umb-dropzone-media @change=${this.#onChange} @progress=${this.#onProgress}></umb-dropzone-media>
`;
}
static styles = [
css`
:host([dragging]) #dropzone {
opacity: 1;
pointer-events: all;
}
[dropzone] {
opacity: 0;
}
#dropzone {
opacity: 0;
pointer-events: none;
display: block;
position: absolute;
inset: 0px;
z-index: 100;
backdrop-filter: opacity(1); /* Removes the built in blur effect */
border-radius: var(--uui-border-radius);
overflow: clip;
border: 1px solid var(--uui-color-focus);
}
#dropzone:after {
content: '';
display: block;
position: absolute;
inset: 0;
border-radius: var(--uui-border-radius);
background-color: var(--uui-color-focus);
opacity: 0.2;
}
`,
];
}
export default UmbMediaCollectionElement;

View File

@@ -218,11 +218,6 @@ export class UmbMediaTableCollectionViewElement extends UmbLitElement {
padding: var(--uui-size-space-3) var(--uui-size-space-6);
}
/* TODO: Should we have embedded padding in the table component? */
umb-table {
padding: 0; /* To fix the embedded padding in the table component. */
}
.container {
display: flex;
justify-content: center;

View File

@@ -0,0 +1,175 @@
import { UmbMediaDetailRepository } from '../../repository/index.js';
import type { UmbMediaDetailModel } from '../../types.js';
import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import type { UUIFileDropzoneEvent } from '@umbraco-cms/backoffice/external/uui';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import {
type UmbAllowedMediaTypeModel,
UmbMediaTypeStructureRepository,
getMediaTypeByFileMimeType,
} from '@umbraco-cms/backoffice/media-type';
import {
UmbTemporaryFileManager,
type UmbTemporaryFileQueueModel,
type UmbTemporaryFileModel,
} from '@umbraco-cms/backoffice/temporary-file';
import { UmbChangeEvent, UmbProgressEvent } from '@umbraco-cms/backoffice/event';
@customElement('umb-dropzone-media')
export class UmbDropzoneMediaElement extends UmbLitElement {
#fileManager = new UmbTemporaryFileManager(this);
#mediaTypeStructure = new UmbMediaTypeStructureRepository(this);
#allowedMediaTypes: Array<UmbAllowedMediaTypeModel> = [];
#mediaDetailRepository = new UmbMediaDetailRepository(this);
@state()
private queue: Array<UmbTemporaryFileModel> = [];
constructor() {
super();
this.observe(this.#fileManager.queue, (queue) => {
this.queue = queue;
const completed = queue.filter((item) => item.status !== 'waiting');
const progress = Math.round((completed.length / queue.length) * 100);
this.dispatchEvent(new UmbProgressEvent(progress));
});
this.#getAllowedMediaTypes();
document.addEventListener('dragenter', this.#handleDragEnter.bind(this));
document.addEventListener('dragleave', this.#handleDragLeave.bind(this));
document.addEventListener('drop', this.#handleDrop.bind(this));
}
disconnectedCallback(): void {
super.disconnectedCallback();
document.removeEventListener('dragenter', this.#handleDragEnter.bind(this));
document.removeEventListener('dragleave', this.#handleDragLeave.bind(this));
document.removeEventListener('drop', this.#handleDrop.bind(this));
}
#handleDragEnter() {
this.toggleAttribute('dragging', true);
}
#handleDragLeave() {
this.toggleAttribute('dragging', false);
}
#handleDrop(event: DragEvent) {
event.preventDefault();
this.toggleAttribute('dragging', false);
}
async #getAllowedMediaTypes() {
const { data } = await this.#mediaTypeStructure.requestAllowedChildrenOf(null);
if (!data) return;
this.#allowedMediaTypes = data.items;
}
#getMediaTypeFromMime(mimetype: string): UmbAllowedMediaTypeModel {
const mediaTypeName = getMediaTypeByFileMimeType(mimetype);
return this.#allowedMediaTypes.find((type) => type.name === mediaTypeName)!;
}
async #uploadHandler(files: Array<File>) {
const queue = files.map((file): UmbTemporaryFileQueueModel => ({ file }));
const uploaded = await this.#fileManager.upload(queue);
return uploaded;
}
async #onFileUpload(event: UUIFileDropzoneEvent) {
const files: Array<File> = event.detail.files;
if (!files.length) return;
const uploads = await this.#uploadHandler(files);
for (const upload of uploads) {
const mediaType = this.#getMediaTypeFromMime(upload.file.type);
const preset: Partial<UmbMediaDetailModel> = {
mediaType: {
unique: mediaType.unique,
collection: null,
},
variants: [
{
culture: null,
segment: null,
name: upload.file.name,
createDate: null,
updateDate: null,
},
],
values: [
{
alias: 'umbracoFile',
value: { src: upload.unique },
culture: null,
segment: null,
},
],
};
const { data } = await this.#mediaDetailRepository.createScaffold(preset);
if (!data) return;
await this.#mediaDetailRepository.create(data, null);
this.dispatchEvent(new UmbChangeEvent());
}
}
render() {
return html`<uui-file-dropzone
id="dropzone"
multiple
@change=${this.#onFileUpload}
label="${this.localize.term('media_dragAndDropYourFilesIntoTheArea')}"
accept=""></uui-file-dropzone>`;
}
static styles = [
css`
:host([dragging]) #dropzone {
opacity: 1;
pointer-events: all;
}
[dropzone] {
opacity: 0;
}
#dropzone {
opacity: 0;
pointer-events: none;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
inset: 0px;
z-index: 100;
backdrop-filter: opacity(1); /* Removes the built in blur effect */
border-radius: var(--uui-border-radius);
overflow: clip;
border: 1px solid var(--uui-color-focus);
}
#dropzone:after {
content: '';
display: block;
position: absolute;
inset: 0;
border-radius: var(--uui-border-radius);
background-color: var(--uui-color-focus);
opacity: 0.2;
}
`,
];
}
export default UmbDropzoneMediaElement;
declare global {
interface HTMLElementTagNameMap {
'umb-dropzone-media': UmbDropzoneMediaElement;
}
}

View File

@@ -0,0 +1 @@
export * from './dropzone-media.element.js';

View File

@@ -1,4 +1,5 @@
import './input-media/index.js';
export * from './dropzone-media/index.js';
export * from './input-media/index.js';
export * from './input-image-cropper/index.js';

View File

@@ -55,7 +55,7 @@ export class UmbInputImageCropperElement extends UmbLitElement {
this.value = assignToFrozenObject(this.value, { src: unique });
this.#manager?.uploadOne(unique, file, 'waiting');
this.#manager?.uploadOne({ unique, file });
this.dispatchEvent(new UmbChangeEvent());
}

View File

@@ -2,7 +2,7 @@ import './components/index.js';
export * from './repository/index.js';
export * from './workspace/index.js';
export * from './tracked-reference/index.js';
export * from './reference/index.js';
export * from './components/index.js';
export * from './entity.js';
export * from './utils/index.js';

View File

@@ -1,2 +1 @@
//export * from './manifests.js';
export * from './repository/index.js';

Some files were not shown because too many files have changed in this diff Show More