diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index ffa016c188..303bf66e74 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -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", diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/index.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/index.ts index ffee1a5b3e..9112ab86e4 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/index.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/index.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateMemberTypePropertyTypeRequestModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateMemberTypePropertyTypeRequestModel.ts index f21270fdb9..aeae062c72 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateMemberTypePropertyTypeRequestModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateMemberTypePropertyTypeRequestModel.ts @@ -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; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateRelationTypeRequestModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateRelationTypeRequestModel.ts deleted file mode 100644 index bc558b9331..0000000000 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateRelationTypeRequestModel.ts +++ /dev/null @@ -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; -}); - diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CurrentUserResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CurrentUserResponseModel.ts index 986c653af0..1a17a0b02d 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CurrentUserResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CurrentUserResponseModel.ts @@ -17,6 +17,7 @@ export type CurrentUserResponseModel = { avatarUrls: Array; languages: Array; hasAccessToAllLanguages: boolean; + hasAccessToSensitiveData: boolean; fallbackPermissions: Array; permissions: Array<(DocumentPermissionPresentationModel | UnknownTypePermissionPresentationModel)>; allowedSections: Array; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DefaultReferenceResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DefaultReferenceResponseModel.ts new file mode 100644 index 0000000000..ee9ea849a5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DefaultReferenceResponseModel.ts @@ -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; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentReferenceResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentReferenceResponseModel.ts new file mode 100644 index 0000000000..07f70a7893 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentReferenceResponseModel.ts @@ -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; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaReferenceResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaReferenceResponseModel.ts new file mode 100644 index 0000000000..51776bc711 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaReferenceResponseModel.ts @@ -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; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MemberTypePropertyTypeModelBaseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MemberTypePropertyTypeModelBaseModel.ts new file mode 100644 index 0000000000..66b045f08b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MemberTypePropertyTypeModelBaseModel.ts @@ -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; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MemberTypePropertyTypeResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MemberTypePropertyTypeResponseModel.ts index 2fb8613c85..3ab12a7228 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MemberTypePropertyTypeResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MemberTypePropertyTypeResponseModel.ts @@ -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; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MemberTypePropertyTypeVisibilityModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MemberTypePropertyTypeVisibilityModel.ts new file mode 100644 index 0000000000..01e1db0fff --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MemberTypePropertyTypeVisibilityModel.ts @@ -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; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedIReferenceResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedIReferenceResponseModel.ts new file mode 100644 index 0000000000..4b8ea5164f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedIReferenceResponseModel.ts @@ -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)>; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedReferenceByIdModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedReferenceByIdModel.ts new file mode 100644 index 0000000000..e7e20d98c6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedReferenceByIdModel.ts @@ -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; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedRelationItemResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedRelationTypeResponseModel.ts similarity index 52% rename from src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedRelationItemResponseModel.ts rename to src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedRelationTypeResponseModel.ts index 47e1960065..951e9e3873 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedRelationItemResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedRelationTypeResponseModel.ts @@ -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; + items: Array; }; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedRelationTypeTreeItemResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedRelationTypeTreeItemResponseModel.ts deleted file mode 100644 index 7790bc4b16..0000000000 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PagedRelationTypeTreeItemResponseModel.ts +++ /dev/null @@ -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; -}; - diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationItemResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationItemResponseModel.ts deleted file mode 100644 index 48a8302000..0000000000 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationItemResponseModel.ts +++ /dev/null @@ -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; -}; - diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationReferenceModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationReferenceModel.ts new file mode 100644 index 0000000000..ab35e260eb --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationReferenceModel.ts @@ -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; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationResponseModel.ts index af7f600b3c..3b2eea7a75 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationResponseModel.ts @@ -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; }; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationTypeBaseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationTypeBaseModel.ts index 93275aa12f..db102160d3 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationTypeBaseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationTypeBaseModel.ts @@ -6,8 +6,6 @@ export type RelationTypeBaseModel = { name: string; isBidirectional: boolean; - parentObjectType?: string | null; - childObjectType?: string | null; isDependency: boolean; }; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationTypeResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationTypeResponseModel.ts index b20537c5d0..9f6eafd317 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationTypeResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/RelationTypeResponseModel.ts @@ -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; }); diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TrackedReferenceContentTypeModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TrackedReferenceContentTypeModel.ts new file mode 100644 index 0000000000..3c5d0602c5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TrackedReferenceContentTypeModel.ts @@ -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; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TrackedReferenceDocumentTypeModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TrackedReferenceDocumentTypeModel.ts new file mode 100644 index 0000000000..bf4b1bee03 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TrackedReferenceDocumentTypeModel.ts @@ -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; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TrackedReferenceMediaTypeModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TrackedReferenceMediaTypeModel.ts new file mode 100644 index 0000000000..d8b64564ea --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TrackedReferenceMediaTypeModel.ts @@ -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; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateMemberTypePropertyTypeRequestModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateMemberTypePropertyTypeRequestModel.ts index 1eb275e6dc..f25dbc33e8 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateMemberTypePropertyTypeRequestModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateMemberTypePropertyTypeRequestModel.ts @@ -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; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateRelationTypeRequestModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateRelationTypeRequestModel.ts deleted file mode 100644 index 9311e54c4c..0000000000 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateRelationTypeRequestModel.ts +++ /dev/null @@ -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; - diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentResource.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentResource.ts index 8536bb1c3b..e667a27657 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentResource.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentResource.ts @@ -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 { + 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 { + 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, + skip?: number, + take?: number, + }): CancelablePromise { + 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 diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/MediaResource.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/MediaResource.ts index 4f4a015050..ad0fe4964b 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/MediaResource.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/MediaResource.ts @@ -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 { + 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 { + 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, + skip?: number, + take?: number, + }): CancelablePromise { + 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 diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/RelationResource.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/RelationResource.ts index 76bbbb9de5..03ed4a82c8 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/RelationResource.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/RelationResource.ts @@ -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 { - 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 diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/RelationTypeResource.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/RelationTypeResource.ts index a3f6109d3a..b8e8141a9f 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/RelationTypeResource.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/RelationTypeResource.ts @@ -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 { + skip?: number, + take?: number, + }): CancelablePromise { 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 { - 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 { - 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 { - 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`, - }, - }); - } - } diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/TrackedReferenceResource.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/TrackedReferenceResource.ts deleted file mode 100644 index 040c7a1345..0000000000 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/TrackedReferenceResource.ts +++ /dev/null @@ -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 { - 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 { - 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, - skip?: number, - take?: number, - filterMustBeIsDependency?: boolean, - }): CancelablePromise { - 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`, - }, - }); - } - -} diff --git a/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts index 161d6e9823..6a3c44ce04 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/browser-handlers.ts @@ -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, diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/document/document.db.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/document/document.db.ts index fdd0e3f23e..a5ab5d2e2f 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/document/document.db.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/document/document.db.ts @@ -17,6 +17,7 @@ import type { DocumentResponseModel, DocumentTreeItemResponseModel, DomainsResponseModel, + DocumentConfigurationResponseModel, } from '@umbraco-cms/backoffice/external/backend-api'; export class UmbDocumentMockDB extends UmbEntityMockDbBase { @@ -39,6 +40,17 @@ export class UmbDocumentMockDB extends UmbEntityMockDbBase 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 => { diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/member-type/member-type.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/member-type/member-type.data.ts index 88b7fa5735..a2466459f4 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/member-type/member-type.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/member-type/member-type.data.ts @@ -24,6 +24,8 @@ export const data: Array = [ 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, diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/relations/relation-type.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/relations/relation-type.data.ts deleted file mode 100644 index 081b6e1f9c..0000000000 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/relations/relation-type.data.ts +++ /dev/null @@ -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 = [ - { - 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 = [ - { - 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 { - private treeData = treeData; - constructor() { - super(data); - } - - //TODO Can relation types have children? - getTreeRoot(): Array { - const rootItems = this.treeData; - return rootItems.map((item) => createEntityTreeItem(item)); - } - - //TODO Can relation types have children? - getTreeItemChildren(id: string): Array { - const childItems = this.treeData.filter((item) => item.parent?.id === id); - return childItems.map((item) => createEntityTreeItem(item)); - } - - getTreeItem(ids: Array): Array { - const items = this.treeData.filter((item) => ids.includes(item.id ?? '')); - return items.map((item) => createEntityTreeItem(item)); - } -} - -export const umbRelationTypeData = new UmbRelationTypeData(); diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/relations/relation.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/relations/relation.data.ts deleted file mode 100644 index 5ea2903bfa..0000000000 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/relations/relation.data.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { UmbEntityData } from '../entity.data.js'; -import type { RelationResponseModel } from '@umbraco-cms/backoffice/external/backend-api'; - -export const data: Array = [ - { - 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 { - 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(); diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/tracked-reference.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/tracked-reference.data.ts index e49f6b009d..868f48c3e7 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/tracked-reference.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/tracked-reference.data.ts @@ -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 = [ +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, ]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/user/user.db.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/user/user.db.ts index 502d924d0b..8ad04cfeff 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/user/user.db.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/user/user.db.ts @@ -61,6 +61,7 @@ class UmbUserMockDB extends UmbEntityMockDbBase { name: firstUser.name, email: firstUser.email, userName: firstUser.email, + hasAccessToSensitiveData: true, avatarUrls: [], hasAccessToAllLanguages: true, languageIsoCode: firstUser.languageIsoCode, diff --git a/src/Umbraco.Web.UI.Client/src/mocks/e2e-handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/e2e-handlers.ts index f86ebb655a..17cf239c92 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/e2e-handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/e2e-handlers.ts @@ -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, ]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/document/detail.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/document/detail.handlers.ts index 85e0ec9ccc..df508ed15e 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/document/detail.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers/document/detail.handlers.ts @@ -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(PagedTrackedReference)); + }), + rest.get(umbracoPath(`${UMB_SLUG}/:id`), (req, res, ctx) => { const id = req.params.id as string; if (!id) return res(ctx.status(400)); diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/media/detail.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/media/detail.handlers.ts index f2eb2098ef..96cb5a1ffc 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/media/detail.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers/media/detail.handlers.ts @@ -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(PagedTrackedReference)); + }), + rest.get(umbracoPath(`${UMB_SLUG}/:id`), (req, res, ctx) => { const id = req.params.id as string; if (!id) return res(ctx.status(400)); diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/index.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/index.ts deleted file mode 100644 index c920b2fd73..0000000000 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './relation/index.js'; -export * from './relation-type/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation-type/detail.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation-type/detail.handlers.ts deleted file mode 100644 index 4d2b87e074..0000000000 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation-type/detail.handlers.ts +++ /dev/null @@ -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(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)); - }), -]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation-type/index.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation-type/index.ts deleted file mode 100644 index 8b9e50e347..0000000000 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation-type/index.ts +++ /dev/null @@ -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]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation-type/slug.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation-type/slug.ts deleted file mode 100644 index 16aae5847e..0000000000 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation-type/slug.ts +++ /dev/null @@ -1 +0,0 @@ -export const UMB_SLUG = '/relation-type'; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation-type/tree.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation-type/tree.handlers.ts deleted file mode 100644 index 985c09b929..0000000000 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation-type/tree.handlers.ts +++ /dev/null @@ -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)); - }), -]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation/index.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation/index.ts deleted file mode 100644 index 46b27bbdb7..0000000000 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { handlers as itemHandlers } from './item.handlers.js'; - -export const relationHandlers = [...itemHandlers]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation/item.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation/item.handlers.ts deleted file mode 100644 index 80bae2824b..0000000000 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation/item.handlers.ts +++ /dev/null @@ -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)); - }), -]; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation/slug.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation/slug.ts deleted file mode 100644 index ba6bc7ffc4..0000000000 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/relations/relation/slug.ts +++ /dev/null @@ -1 +0,0 @@ -export const UMB_SLUG = '/relation'; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/tracked-reference.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/tracked-reference.handlers.ts deleted file mode 100644 index 8c07ee88e4..0000000000 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/tracked-reference.handlers.ts +++ /dev/null @@ -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(PagedTrackedReference)); - }), -]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/collection/default/collection-default.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/collection/default/collection-default.element.ts index 3bacd4e26a..087dd2e362 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/collection/default/collection-default.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/collection/default/collection-default.element.ts @@ -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() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/collection/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/collection/types.ts index a83bebffbb..f35fb988fb 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/collection/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/collection/types.ts @@ -14,6 +14,7 @@ export interface UmbCollectionConfiguration { unique?: string; dataTypeId?: string; allowedEntityBulkActions?: UmbCollectionBulkActionPermissions; + layouts?: Array; 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; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-upload-field/input-upload-field.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-upload-field/input-upload-field.element.ts index 391fd80510..ad87b45ca5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-upload-field/input-upload-field.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-upload-field/input-upload-field.element.ts @@ -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); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/table/table.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/table/table.element.ts index d140299895..43234edd3d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/table/table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/table/table.element.ts @@ -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 { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/event/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/event/index.ts index af975b4ddc..7863291fc0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/event/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/event/index.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/event/progress.event.ts b/src/Umbraco.Web.UI.Client/src/packages/core/event/progress.event.ts new file mode 100644 index 0000000000..8d83b5d99a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/event/progress.event.ts @@ -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; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/icon-picker/icon-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/icon-picker/icon-picker-modal.element.ts index 9e28e70b4e..91fbb6af8e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/icon-picker/icon-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/icon-picker/icon-picker-modal.element.ts @@ -70,16 +70,16 @@ export class UmbIconPickerModalElement extends UmbModalBaseElement + @change=${this.#onColorChange}> ${ // TODO: Missing translation for the color aliases. this._colorList.map( (color) => html` `, diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/collection-view/config/layout-configuration/property-editor-ui-collection-view-layout-configuration.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/collection-view/config/layout-configuration/property-editor-ui-collection-view-layout-configuration.element.ts index 7863ff037b..40f7d221dd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/collection-view/config/layout-configuration/property-editor-ui-collection-view-layout-configuration.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/collection-view/config/layout-configuration/property-editor-ui-collection-view-layout-configuration.element.ts @@ -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; + value?: Array; @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`
- ${this.value - ? repeat( - this.value, - (layout, index) => '' + layout.name + layout.icon, - (layout, index) => - html`
- ${layout.isSystem - ? this.renderSystemFieldRow(layout, index) - : this.renderCustomFieldRow(layout, index)} -
`, - ) - : ''} + if (!this.value) return nothing; + return html` +
+ ${repeat( + this.value, + (layout, index) => '' + index + layout.name + layout.icon, + (layout, index) => this.#renderLayout(layout, index), + )}
- `; + + `; } - #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` +
+ - if (parts.length === 2) { - const [icon, color] = parts; - const varName = extractUmbColorVariable(color.replace('color-', '')); - return { icon, color: varName }; - } else { - const [icon] = parts; - return { icon }; - } - } + this.#onIconChange(icon, index)}> + ${when( + icon.color, + () => html``, + () => html``, + )} + - renderSystemFieldRow(layout: LayoutConfig, index: number) { - const icon = this.#iconReader(layout.icon ?? ''); + this.#onChangeLabel(e, index)}> - return html` - - - ${index} - ${ifDefined(layout.name)} (system field) - this.#onChangeSelected(e, index)}> - `; - } +
+ ${layout.collectionView} +
- renderCustomFieldRow(layout: LayoutConfig, index: number) { - const icon = this.#iconReader(layout.icon ?? ''); - - return html` this.#onIconChange(index)}> - ${icon.color - ? html`` - : html``} - - ${index} - this.#onChangeName(e, index)}> - this.#onChangePath(e, index)}> - this.#onRemove(index)}>`; +
+ this.#onRemove(index)}> +
+
+ `; } 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; } `, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/detail-data-source.interface.ts b/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/detail-data-source.interface.ts index c63c57a555..b0f21617e5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/detail-data-source.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/detail-data-source.interface.ts @@ -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 { new (host: UmbControllerHost): UmbDetailDataSource; } -export interface UmbDetailDataSource { +export interface UmbDetailDataSource extends UmbReadDetailDataSource { createScaffold(preset?: Partial): Promise>; create(data: DetailType, parentUnique: string | null): Promise>; - read(unique: string): Promise>; update(data: DetailType): Promise>; delete(unique: string): Promise; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/detail-repository.interface.ts b/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/detail-repository.interface.ts index 6dc9fe7003..d2d4832fa0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/detail-repository.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/detail-repository.interface.ts @@ -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 extends UmbApi { +export interface UmbDetailRepository extends UmbReadDetailRepository, UmbApi { createScaffold(preset?: Partial): Promise>; - requestByUnique(unique: string): Promise>; - byUnique(unique: string): Promise>; create(data: DetailModelType, parentUnique: string | null): Promise>; save(data: DetailModelType): Promise>; delete(unique: string): Promise; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/index.ts index 72321c033e..f190db5763 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/index.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/read/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/read/index.ts new file mode 100644 index 0000000000..cdbf84eea0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/read/index.ts @@ -0,0 +1,5 @@ +export type { + UmbReadDetailDataSource, + UmbReadDetailDataSourceConstructor, +} from './read-detail-data-source.interface.js'; +export type { UmbReadDetailRepository } from './read-detail-repository.interface.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/read/read-detail-data-source.interface.ts b/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/read/read-detail-data-source.interface.ts new file mode 100644 index 0000000000..9894043773 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/read/read-detail-data-source.interface.ts @@ -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 { + new (host: UmbControllerHost): UmbReadDetailDataSource; +} + +export interface UmbReadDetailDataSource { + read(unique: string): Promise>; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/read/read-detail-repository.interface.ts b/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/read/read-detail-repository.interface.ts new file mode 100644 index 0000000000..702dfb9a1f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/repository/detail/read/read-detail-repository.interface.ts @@ -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 extends UmbApi { + requestByUnique(unique: string): Promise>; + byUnique(unique: string): Promise>; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/temporary-file/temporary-file-manager.class.ts b/src/Umbraco.Web.UI.Client/src/packages/core/temporary-file/temporary-file-manager.class.ts index d14ce52a35..2f349c4bbf 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/temporary-file/temporary-file-manager.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/temporary-file/temporary-file-manager.class.ts @@ -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 { file: File; - status?: TemporaryFileStatus; } export class UmbTemporaryFileManager extends UmbControllerBase { #temporaryFileRepository; - #queue = new UmbArrayState([], (item) => item.unique); + #queue = new UmbArrayState([], (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> { + 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) { - this.#queue.append(queueItems); - this.handleQueue(); + async upload(queueItems: Array): Promise> { + 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 = []; 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; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/manifests.ts index db2a31585c..4624c1bb72 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/manifests.ts @@ -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, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-collection/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-collection/manifests.ts new file mode 100644 index 0000000000..e2e24b46d8 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-collection/manifests.ts @@ -0,0 +1,25 @@ +import type { ManifestWorkspaceView } from '@umbraco-cms/backoffice/extension-registry'; + +export const manifests: Array = [ + { + 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', + }, + ], + }, +]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/collection/document-workspace-view-collection.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-collection/workspace-view-collection.element.ts similarity index 64% rename from src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/collection/document-workspace-view-collection.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-collection/workspace-view-collection.element.ts index 47f4fff704..8a80c96069 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/collection/document-workspace-view-collection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-collection/workspace-view-collection.element.ts @@ -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('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``; + if (this._loading) return nothing; + return html``; } } -export default UmbDocumentWorkspaceViewCollectionElement; +export default UmbWorkspaceViewCollectionElement; declare global { interface HTMLElementTagNameMap { - 'umb-document-workspace-view-collection': UmbDocumentWorkspaceViewCollectionElement; + 'umb-workspace-view-collection': UmbWorkspaceViewCollectionElement; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/index.ts index 1babbbae1f..81c6f4dbfc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/index.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts index d66f93d783..a7f20868bd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/collection/views/table/document-table-collection-view.element.ts @@ -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; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/index.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/index.ts index 862805500c..e5ac096a12 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/index.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/manifests.ts index 56fe3f53bb..1d2db8ffa2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/manifests.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/unpublish-modal/document-unpublish-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/unpublish-modal/document-unpublish-modal.element.ts index 8d92f3c8ba..de333e1e20 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/unpublish-modal/document-unpublish-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/unpublish-modal/document-unpublish-modal.element.ts @@ -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(this); - #trackedReferencesRepository = new UmbDocumentTrackedReferenceRepository(this); + #referencesRepository = new UmbDocumentReferenceRepository(this); @state() _options: Array = []; @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` - + ` : nothing} - ${this._hasTrackedReferences - ? html` + ${this._hasReferences + ? html` 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); diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/components/document-tracked-reference-table.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/components/document-reference-table.element.ts similarity index 59% rename from src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/components/document-tracked-reference-table.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/components/document-reference-table.element.ts index 0a2570b6d9..e764d3322a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/components/document-tracked-reference-table.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/components/document-reference-table.element.ts @@ -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 = []; + _items: Array = []; /** * 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` - - + + - ${item.nodeName} - ${item.contentTypeName} + ${item.name} + ${this.#getContentTypeName(item)} `, )} ${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; } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/components/document-reference-table.stories.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/components/document-reference-table.stories.ts new file mode 100644 index 0000000000..e2ed14db4d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/components/document-reference-table.stories.ts @@ -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 = { + 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: ` + + `, + }, + }, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Overview: Story = {}; + +export const SlimTable: Story = { + decorators: [ + (story) => { + return html`
${story()}
`; + }, + ], + parameters: { + docs: { + source: { + language: 'html', + code: ` + + `, + }, + }, + }, +}; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/components/index.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/components/index.ts new file mode 100644 index 0000000000..93cf4127b1 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/components/index.ts @@ -0,0 +1 @@ +export * from './document-reference-table.element.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/index.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/index.ts similarity index 69% rename from src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/index.ts rename to src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/index.ts index 378cd7b5d8..1263e6be41 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/index.ts @@ -1,3 +1,2 @@ -//export * from './manifests.js'; export * from './components/index.js'; export * from './repository/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/manifests.ts similarity index 63% rename from src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/manifests.ts rename to src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/manifests.ts index 08d464db49..4e1826b900 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/manifests.ts @@ -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]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/repository/document-reference.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/repository/document-reference.repository.ts new file mode 100644 index 0000000000..628592c62c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/repository/document-reference.repository.ts @@ -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; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/repository/document-reference.server.data.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/repository/document-reference.server.data.ts new file mode 100644 index 0000000000..1b8cae5e0c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/repository/document-reference.server.data.ts @@ -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 })); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/repository/index.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/repository/index.ts new file mode 100644 index 0000000000..4cb57bf4b1 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/repository/index.ts @@ -0,0 +1 @@ +export * from './document-reference.repository.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/repository/manifests.ts new file mode 100644 index 0000000000..bf5b524279 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/reference/repository/manifests.ts @@ -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]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/components/document-tracked-reference-table.stories.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/components/document-tracked-reference-table.stories.ts deleted file mode 100644 index b92d7bdf22..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/components/document-tracked-reference-table.stories.ts +++ /dev/null @@ -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 = { - 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: ` - - `, - }, - }, - }, -}; - -export default meta; - -type Story = StoryObj; - -export const Overview: Story = {}; - -export const SlimTable: Story = { - decorators: [ - (story) => { - return html`
${story()}
`; - }, - ], - parameters: { - docs: { - source: { - language: 'html', - code: ` - - `, - }, - }, - }, -}; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/components/index.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/components/index.ts deleted file mode 100644 index 7738a990a5..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/components/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './document-tracked-reference-table.element.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/repository/document-tracked-reference.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/repository/document-tracked-reference.repository.ts deleted file mode 100644 index a7dc589cec..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/repository/document-tracked-reference.repository.ts +++ /dev/null @@ -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; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/repository/document-tracked-reference.server.data.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/repository/document-tracked-reference.server.data.ts deleted file mode 100644 index 818973aa0b..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/repository/document-tracked-reference.server.data.ts +++ /dev/null @@ -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} 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} 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} 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, - }), - ); - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/repository/index.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/repository/index.ts deleted file mode 100644 index 5c3d3be88a..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/repository/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './document-tracked-reference.repository.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/repository/manifests.ts deleted file mode 100644 index 21b59fd7f1..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/repository/manifests.ts +++ /dev/null @@ -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]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace-editor.element.ts index bca7f3c99b..2f4b916f6e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace-editor.element.ts @@ -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}`); }, }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/manifests.ts index 344e7ac8b7..dbd1616e94 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/manifests.ts @@ -25,27 +25,6 @@ const workspace: ManifestWorkspaces = { }; const workspaceViews: Array = [ - { - 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', diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/info/document-workspace-view-info-reference.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/info/document-workspace-view-info-reference.element.ts index fde110c12f..973fa057aa 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/info/document-workspace-view-info-reference.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/info/document-workspace-view-info-reference.element.ts @@ -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 = []; + private _items?: Array = []; 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` Status Type Name Type - - Relation - ${repeat( this._items, - (item) => item.nodeId, + (item) => item.id, (item) => html` - + - - ${item.nodeName} - + ${isDocumentReference(item) + ? html` + ${item.name} + ` + : item.name} - ${item.nodePublished + ${this.#getPublishedStatus(item) ? this.localize.term('content_published') : this.localize.term('content_unpublished')} - ${item.contentTypeName} - ${item.nodeType} - ${item.relationTypeName} + ${this.#getContentTypeName(item)} + ${this.#getContentType(item)} `, )} @@ -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); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/index.ts index 4a54461e21..60142d5186 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/index.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/utils/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/utils/index.ts new file mode 100644 index 0000000000..b67055a38e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/utils/index.ts @@ -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; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.element.ts index 79ca338c7a..dd74cf2241 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.element.ts @@ -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` - - + ${when(this._progress >= 0, () => html``)} + `; } - - 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; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/views/table/media-table-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/views/table/media-table-collection-view.element.ts index 8d093bf433..96b09094ba 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/views/table/media-table-collection-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/views/table/media-table-collection-view.element.ts @@ -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; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/dropzone-media/dropzone-media.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/dropzone-media/dropzone-media.element.ts new file mode 100644 index 0000000000..6a03dc5e19 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/dropzone-media/dropzone-media.element.ts @@ -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 = []; + #mediaDetailRepository = new UmbMediaDetailRepository(this); + + @state() + private queue: Array = []; + + 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) { + const queue = files.map((file): UmbTemporaryFileQueueModel => ({ file })); + const uploaded = await this.#fileManager.upload(queue); + return uploaded; + } + + async #onFileUpload(event: UUIFileDropzoneEvent) { + const files: Array = 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 = { + 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``; + } + + 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; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/dropzone-media/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/dropzone-media/index.ts new file mode 100644 index 0000000000..a6c28ed09c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/dropzone-media/index.ts @@ -0,0 +1 @@ +export * from './dropzone-media.element.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/index.ts index 3c48dc1e29..d884d15b41 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/index.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/input-image-cropper.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/input-image-cropper.element.ts index 902f1f082a..673440b690 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/input-image-cropper.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-image-cropper/input-image-cropper.element.ts @@ -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()); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/index.ts index 226014f2a5..3bf1a83c99 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/index.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/index.ts similarity index 53% rename from src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/index.ts rename to src/Umbraco.Web.UI.Client/src/packages/media/media/reference/index.ts index 9f92b38d91..3d76f338dd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/index.ts @@ -1,2 +1 @@ -//export * from './manifests.js'; export * from './repository/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/manifests.ts similarity index 61% rename from src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/manifests.ts rename to src/Umbraco.Web.UI.Client/src/packages/media/media/reference/manifests.ts index 1c809b7055..4e1826b900 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/tracked-reference/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/manifests.ts @@ -1,5 +1,3 @@ import { manifests as repositoryManifests } from './repository/manifests.js'; -export const UMB_TRACKED_REFERENCE_DOCUMENT = 'Umb.TrackedReference.Document'; - export const manifests = [...repositoryManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/repository/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/repository/index.ts new file mode 100644 index 0000000000..110660f040 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/repository/index.ts @@ -0,0 +1 @@ +export * from './media-reference.repository.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/repository/manifests.ts new file mode 100644 index 0000000000..76eaf91825 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/repository/manifests.ts @@ -0,0 +1,12 @@ +import type { ManifestRepository } from '@umbraco-cms/backoffice/extension-registry'; + +export const UMB_MEDIA_REFERENCE_REPOSITORY_ALIAS = 'Umb.Repository.Media.Reference'; + +const repository: ManifestRepository = { + type: 'repository', + alias: UMB_MEDIA_REFERENCE_REPOSITORY_ALIAS, + name: 'Media Reference Repository', + api: () => import('./media-reference.repository.js'), +}; + +export const manifests = [repository]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/repository/media-reference.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/repository/media-reference.repository.ts new file mode 100644 index 0000000000..dd7bb49c50 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/repository/media-reference.repository.ts @@ -0,0 +1,19 @@ +import { UmbMediaReferenceServerDataSource } from './media-reference.server.data.js'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; + +export class UmbMediaReferenceRepository extends UmbControllerBase { + #referenceSource: UmbMediaReferenceServerDataSource; + + constructor(host: UmbControllerHost) { + super(host); + this.#referenceSource = new UmbMediaReferenceServerDataSource(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 UmbMediaReferenceRepository; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/repository/media-reference.server.data.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/repository/media-reference.server.data.ts new file mode 100644 index 0000000000..b8f1177398 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/reference/repository/media-reference.server.data.ts @@ -0,0 +1,31 @@ +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { MediaResource } from '@umbraco-cms/backoffice/external/backend-api'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; + +/** + * @export + * @class UmbMediaReferenceServerDataSource + * @implements {RepositoryDetailDataSource} + */ +export class UmbMediaReferenceServerDataSource { + #host: UmbControllerHost; + + /** + * Creates an instance of UmbMediaReferenceServerDataSource. + * @param {UmbControllerHost} host + * @memberof UmbMediaReferenceServerDataSource + */ + constructor(host: UmbControllerHost) { + this.#host = host; + } + + /** + * Fetches the item for the given id from the server + * @param {Array} ids + * @return {*} + * @memberof UmbMediaReferenceServerDataSource + */ + async getReferencedBy(id: string, skip = 0, take = 20) { + return await tryExecuteAndNotify(this.#host, MediaResource.getMediaByIdReferencedBy({ id, skip, take })); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/repository/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/repository/index.ts deleted file mode 100644 index 503cfaa2a9..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/repository/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './media-tracked-reference.repository.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/repository/manifests.ts deleted file mode 100644 index 808e2429e1..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/repository/manifests.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { ManifestRepository } from '@umbraco-cms/backoffice/extension-registry'; - -export const UMB_MEDIA_TRACKED_REFERENCE_REPOSITORY_ALIAS = 'Umb.Repository.Media.TrackedReference'; - -const repository: ManifestRepository = { - type: 'repository', - alias: UMB_MEDIA_TRACKED_REFERENCE_REPOSITORY_ALIAS, - name: 'Media Tracked Reference Repository', - api: () => import('./media-tracked-reference.repository.js'), -}; - -export const manifests = [repository]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/repository/media-tracked-reference.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/repository/media-tracked-reference.repository.ts deleted file mode 100644 index fc56304143..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/repository/media-tracked-reference.repository.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { UmbMediaTrackedReferenceServerDataSource } from './media-tracked-reference.server.data.js'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; - -export class UmbMediaTrackedReferenceRepository extends UmbControllerBase { - #trackedReferenceSource: UmbMediaTrackedReferenceServerDataSource; - - constructor(host: UmbControllerHost) { - super(host); - this.#trackedReferenceSource = new UmbMediaTrackedReferenceServerDataSource(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 UmbMediaTrackedReferenceRepository; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/repository/media-tracked-reference.server.data.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/repository/media-tracked-reference.server.data.ts deleted file mode 100644 index 1031abc22d..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/tracked-reference/repository/media-tracked-reference.server.data.ts +++ /dev/null @@ -1,75 +0,0 @@ -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { TrackedReferenceResource } from '@umbraco-cms/backoffice/external/backend-api'; -import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; - -/** - * @export - * @class UmbUserGroupCollectionServerDataSource - * @implements {RepositoryDetailDataSource} - */ -export class UmbMediaTrackedReferenceServerDataSource { - #host: UmbControllerHost; - - /** - * Creates an instance of UmbMediaTrackedReferenceServerDataSource. - * @param {UmbControllerHost} host - * @memberof UmbMediaTrackedReferenceServerDataSource - */ - constructor(host: UmbControllerHost) { - this.#host = host; - } - - /** - * Fetches the item for the given id from the server - * @param {Array} 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} ids - * @return {*} - * @memberof UmbMediaTrackedReferenceServerDataSource - */ - 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} ids - * @return {*} - * @memberof UmbMediaTrackedReferenceServerDataSource - */ - async getTrackedReferenceItem(id: string[], skip = 0, take = 20, filterMustBeIsDependency = true) { - return await tryExecuteAndNotify( - this.#host, - TrackedReferenceResource.getTrackedReferenceItem({ - id, - skip, - take, - filterMustBeIsDependency, - }), - ); - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/manifests.ts index c94ee5f8a7..3f9e5c9c0e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/manifests.ts @@ -17,27 +17,6 @@ const workspace: ManifestWorkspaces = { }; const workspaceViews: Array = [ - { - type: 'workspaceView', - alias: 'Umb.WorkspaceView.Media.Collection', - name: 'Media Workspace Collection View', - element: () => import('./views/collection/media-workspace-view-collection.element.js'), - weight: 300, - meta: { - label: 'Collection', - pathname: 'collection', - icon: 'icon-grid', - }, - conditions: [ - { - alias: 'Umb.Condition.WorkspaceAlias', - match: workspace.alias, - }, - { - alias: 'Umb.Condition.WorkspaceHasCollection', - }, - ], - }, { type: 'workspaceView', alias: 'Umb.WorkspaceView.Media.Edit', diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/views/collection/media-workspace-view-collection.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/views/collection/media-workspace-view-collection.element.ts deleted file mode 100644 index a8d12c291f..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/views/collection/media-workspace-view-collection.element.ts +++ /dev/null @@ -1,82 +0,0 @@ -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_MEDIA_COLLECTION_ALIAS, UMB_MEDIA_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/media'; -import type { - UmbCollectionBulkActionPermissions, - UmbCollectionConfiguration, -} from '@umbraco-cms/backoffice/collection'; -import type { UmbDataTypeDetailModel } from '@umbraco-cms/backoffice/data-type'; -import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry'; - -@customElement('umb-media-workspace-view-collection') -export class UmbMediaWorkspaceViewCollectionElement extends UmbLitElement implements UmbWorkspaceViewElement { - @state() - private _config?: UmbCollectionConfiguration; - - @state() - private _mediaUnique?: string; - - #dataTypeDetailRepository = new UmbDataTypeDetailRepository(this); - - constructor() { - super(); - this.#observeConfig(); - } - - async #observeConfig() { - this.consumeContext(UMB_MEDIA_WORKSPACE_CONTEXT, (workspaceContext) => { - this.observe(workspaceContext.unique, (unique) => { - this._mediaUnique = unique; - }); - this.observe( - workspaceContext.structure.ownerContentType, - async (mediaType) => { - if (!mediaType || !mediaType.collection) return; - - const dataTypeUnique = mediaType.collection.unique; - - if (dataTypeUnique) { - await this.#dataTypeDetailRepository.requestByUnique(dataTypeUnique); - this.observe( - await this.#dataTypeDetailRepository.byUnique(dataTypeUnique), - (dataType) => { - if (!dataType) return; - this._config = this.#mapDataTypeConfigToCollectionConfig(dataType); - }, - '_observeConfigDataType', - ); - } - }, - '_observeConfigMediaType', - ); - }); - } - - #mapDataTypeConfigToCollectionConfig(dataType: UmbDataTypeDetailModel): UmbCollectionConfiguration { - const config = new UmbPropertyEditorConfigCollection(dataType.values); - return { - unique: this._mediaUnique, - allowedEntityBulkActions: config?.getValueByAlias('bulkActionPermissions'), - orderBy: config?.getValueByAlias('orderBy') ?? 'updateDate', - orderDirection: config?.getValueByAlias('orderDirection') ?? 'asc', - pageSize: Number(config?.getValueByAlias('pageSize')) ?? 50, - useInfiniteEditor: config?.getValueByAlias('useInfiniteEditor') ?? false, - userDefinedProperties: config?.getValueByAlias('includeProperties'), - }; - } - - render() { - if (!this._config?.unique) return nothing; - return html``; - } -} - -export default UmbMediaWorkspaceViewCollectionElement; - -declare global { - interface HTMLElementTagNameMap { - 'umb-media-workspace-view-collection': UmbMediaWorkspaceViewCollectionElement; - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/views/info/media-workspace-view-info-reference.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/views/info/media-workspace-view-info-reference.element.ts index f0d7c333bb..f5e5eda83c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/views/info/media-workspace-view-info-reference.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/views/info/media-workspace-view-info-reference.element.ts @@ -2,14 +2,19 @@ import { css, html, customElement, state, nothing, repeat, property } from '@umb 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 { UmbMediaTrackedReferenceRepository } from '@umbraco-cms/backoffice/media'; +import { UmbMediaReferenceRepository } from '@umbraco-cms/backoffice/media'; import { UMB_WORKSPACE_MODAL, UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal'; +import { + isDefaultReference, + isDocumentReference, + isMediaReference, + type UmbReferenceModel, +} from '@umbraco-cms/backoffice/relations'; @customElement('umb-media-workspace-view-info-reference') export class UmbMediaWorkspaceViewInfoReferenceElement extends UmbLitElement { #itemsPerPage = 10; - #trackedReferenceRepository; + #referenceRepository; @property() mediaUnique = ''; @@ -24,11 +29,11 @@ export class UmbMediaWorkspaceViewInfoReferenceElement extends UmbLitElement { private _total = 0; @state() - private _items?: Array = []; + private _items?: Array = []; constructor() { super(); - this.#trackedReferenceRepository = new UmbMediaTrackedReferenceRepository(this); + this.#referenceRepository = new UmbMediaReferenceRepository(this); new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL) .addAdditionalPath('media') @@ -45,7 +50,7 @@ export class UmbMediaWorkspaceViewInfoReferenceElement extends UmbLitElement { } async #getReferences() { - const { data } = await this.#trackedReferenceRepository.requestTrackedReference( + const { data } = await this.#referenceRepository.requestReferencedBy( this.mediaUnique, this._currentPage - 1 * this.#itemsPerPage, this.#itemsPerPage, @@ -63,12 +68,54 @@ export class UmbMediaWorkspaceViewInfoReferenceElement 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` - Referenced by the following items - - + return html` @@ -76,34 +123,34 @@ export class UmbMediaWorkspaceViewInfoReferenceElement extends UmbLitElement { Status Type Name Type - - Relation - ${repeat( this._items, - (item) => item.nodeId, + (item) => item.id, (item) => html` - + - - ${item.nodeName} - + ${isDocumentReference(item) + ? html` + + ${item.name} + + ` + : item.name} - ${item.nodePublished + ${this.#getPublishedStatus(item) ? this.localize.term('content_published') : this.localize.term('content_unpublished')} - ${item.contentTypeName} - ${item.nodeType} - ${item.relationTypeName} + ${this.#getContentTypeName(item)} + ${this.#getContentType(item)} `, )} @@ -129,10 +176,6 @@ export class UmbMediaWorkspaceViewInfoReferenceElement extends UmbLitElement { static styles = [ UmbTextStyles, css` - .link-cell { - font-weight: bold; - } - uui-table-cell:not(.link-cell) { color: var(--uui-color-text-alt); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member-group/collection/views/table/member-group-table-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member-group/collection/views/table/member-group-table-collection-view.element.ts index a6d8cd3fc2..2065ad1bdb 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member-group/collection/views/table/member-group-table-collection-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member-group/collection/views/table/member-group-table-collection-view.element.ts @@ -70,10 +70,6 @@ export class UmbMemberGroupTableCollectionViewElement extends UmbLitElement { display: flex; flex-direction: column; } - - umb-table { - padding: 0; - } `, ]; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/detail/member-type-detail.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/detail/member-type-detail.server.data-source.ts index e27325182b..cf717ef3df 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/detail/member-type-detail.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member-type/repository/detail/member-type-detail.server.data-source.ts @@ -147,6 +147,8 @@ export class UmbMemberTypeServerDataSource implements UmbDetailDataSource import('./relation-type-collection.repository.js'), +}; + +export const manifests = [repository]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/repository/relation-type-collection.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/repository/relation-type-collection.repository.ts new file mode 100644 index 0000000000..f2222a3bde --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/repository/relation-type-collection.repository.ts @@ -0,0 +1,21 @@ +import type { UmbRelationTypeCollectionFilterModel } from '../types.js'; +import { UmbRelationTypeCollectionServerDataSource } from './relation-type-collection.server.data-source.js'; +import type { UmbRelationTypeCollectionDataSource } from './types.js'; +import type { UmbCollectionRepository } from '@umbraco-cms/backoffice/collection'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; + +export class UmbRelationTypeCollectionRepository implements UmbCollectionRepository { + #collectionSource: UmbRelationTypeCollectionDataSource; + + constructor(host: UmbControllerHost) { + this.#collectionSource = new UmbRelationTypeCollectionServerDataSource(host); + } + + async requestCollection(filter: UmbRelationTypeCollectionFilterModel) { + return this.#collectionSource.getCollection(filter); + } + + destroy(): void {} +} + +export default UmbRelationTypeCollectionRepository; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/repository/relation-type-collection.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/repository/relation-type-collection.server.data-source.ts new file mode 100644 index 0000000000..b1fb2a947a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/repository/relation-type-collection.server.data-source.ts @@ -0,0 +1,71 @@ +import type { UmbRelationTypeCollectionFilterModel } from '../types.js'; +import type { UmbRelationTypeDetailModel } from '../../types.js'; +import { UMB_RELATION_TYPE_ENTITY_TYPE } from '../../entity.js'; +import type { UmbCollectionDataSource } from '@umbraco-cms/backoffice/collection'; +import { RelationTypeResource } from '@umbraco-cms/backoffice/external/backend-api'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; + +/** + * A data source that fetches the relation type collection data from the server. + * @export + * @class UmbRelationTypeCollectionServerDataSource + * @implements {UmbCollectionDataSource} + */ +export class UmbRelationTypeCollectionServerDataSource implements UmbCollectionDataSource { + #host: UmbControllerHost; + + /** + * Creates an instance of UmbRelationTypeCollectionServerDataSource. + * @param {UmbControllerHost} host + * @memberof UmbRelationTypeCollectionServerDataSource + */ + constructor(host: UmbControllerHost) { + this.#host = host; + } + + /** + * Gets the relation type collection filtered by the given filter. + * @param {UmbRelationTypeCollectionFilterModel} filter + * @return {*} + * @memberof UmbRelationTypeCollectionServerDataSource + */ + async getCollection(filter: UmbRelationTypeCollectionFilterModel) { + const { data, error } = await tryExecuteAndNotify(this.#host, RelationTypeResource.getRelationType(filter)); + + if (data) { + const items = data.items.map((item) => { + const model: UmbRelationTypeDetailModel = { + alias: item.alias || '', + child: item.childObject + ? { + objectType: { + unique: item.childObject.id, + name: item.childObject.name || '', + }, + } + : null, + entityType: UMB_RELATION_TYPE_ENTITY_TYPE, + isBidirectional: item.isBidirectional, + isDependency: item.isDependency, + name: item.name, + parent: item.parentObject + ? { + objectType: { + unique: item.parentObject.id, + name: item.parentObject.name || '', + }, + } + : null, + unique: item.id, + }; + + return model; + }); + + return { data: { items, total: data.total } }; + } + + return { error }; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/repository/types.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/repository/types.ts new file mode 100644 index 0000000000..5e6ae8f9ec --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/repository/types.ts @@ -0,0 +1,8 @@ +import type { UmbRelationTypeDetailModel } from '../../types.js'; +import type { UmbRelationTypeCollectionFilterModel } from '../types.js'; +import type { UmbCollectionDataSource } from '@umbraco-cms/backoffice/collection'; + +export type UmbRelationTypeCollectionDataSource = UmbCollectionDataSource< + UmbRelationTypeDetailModel, + UmbRelationTypeCollectionFilterModel +>; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/types.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/types.ts new file mode 100644 index 0000000000..ee142cf7de --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/types.ts @@ -0,0 +1,4 @@ +export interface UmbRelationTypeCollectionFilterModel { + skip?: number; + take?: number; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/views/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/views/manifests.ts new file mode 100644 index 0000000000..f24685ce74 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/views/manifests.ts @@ -0,0 +1,22 @@ +import { UMB_COLLECTION_ALIAS_CONDITION } from '@umbraco-cms/backoffice/collection'; +import type { ManifestCollectionView } from '@umbraco-cms/backoffice/extension-registry'; + +const tableCollectionView: ManifestCollectionView = { + type: 'collectionView', + alias: 'Umb.CollectionView.RelationType.Table', + name: 'Relation Type Table Collection View', + js: () => import('./table/relation-type-table-collection-view.element.js'), + meta: { + label: 'Table', + icon: 'icon-list', + pathName: 'table', + }, + conditions: [ + { + alias: UMB_COLLECTION_ALIAS_CONDITION, + match: 'Umb.Collection.RelationType', + }, + ], +}; + +export const manifests = [tableCollectionView]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/views/table/relation-type-table-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/views/table/relation-type-table-collection-view.element.ts new file mode 100644 index 0000000000..da7f76d599 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/collection/views/table/relation-type-table-collection-view.element.ts @@ -0,0 +1,83 @@ +import type { UmbRelationTypeDetailModel } from '../../../types.js'; +import type { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collection'; +import { UMB_DEFAULT_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/collection'; +import type { UmbTableColumn, UmbTableConfig, UmbTableItem } from '@umbraco-cms/backoffice/components'; +import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; + +@customElement('umb-relation-type-table-collection-view') +export class UmbRelationTypeTableCollectionViewElement extends UmbLitElement { + @state() + private _tableConfig: UmbTableConfig = { + allowSelection: false, + }; + + @state() + private _tableColumns: Array = [ + { + name: 'Relation Type', + alias: 'relationTypeName', + }, + ]; + + @state() + private _tableItems: Array = []; + + #collectionContext?: UmbDefaultCollectionContext; + + constructor() { + super(); + + this.consumeContext(UMB_DEFAULT_COLLECTION_CONTEXT, (instance) => { + this.#collectionContext = instance; + this.#observeCollectionItems(); + }); + } + + #observeCollectionItems() { + if (!this.#collectionContext) return; + this.observe(this.#collectionContext.items, (items) => this.#createTableItems(items), 'umbCollectionItemsObserver'); + } + + #createTableItems(relationTypes: Array) { + this._tableItems = relationTypes.map((relationType) => { + return { + id: relationType.unique, + icon: 'icon-trafic', + data: [ + { + columnAlias: 'relationTypeName', + value: html`${relationType.name}`, + }, + ], + }; + }); + } + + render() { + return html` + + `; + } + + static styles = [ + UmbTextStyles, + css` + :host { + display: flex; + flex-direction: column; + } + `, + ]; +} + +export default UmbRelationTypeTableCollectionViewElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-relation-type-table-collection-view': UmbRelationTypeTableCollectionViewElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/entity-actions/create.action.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/entity-actions/create.action.ts deleted file mode 100644 index 7002572068..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/entity-actions/create.action.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { UmbEntityActionArgs } from '@umbraco-cms/backoffice/entity-action'; -import { UmbEntityActionBase } from '@umbraco-cms/backoffice/entity-action'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; - -export class UmbCreateRelationTypeEntityAction extends UmbEntityActionBase { - constructor(host: UmbControllerHost, args: UmbEntityActionArgs) { - super(host, args); - } - - async execute() { - // TODO: Generate the href or retrieve it from something? - history.pushState( - null, - '', - `section/settings/workspace/relation-type/create/parent/${this.args.entityType}/${this.args.unique}`, - ); - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/entity-actions/manifests.ts deleted file mode 100644 index 1456a8d0bb..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/entity-actions/manifests.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { UMB_RELATION_TYPE_REPOSITORY_ALIAS } from '../repository/manifests.js'; -import { UMB_RELATION_TYPE_ENTITY_TYPE, UMB_RELATION_TYPE_ROOT_ENTITY_TYPE } from '../index.js'; -import { UmbCreateRelationTypeEntityAction } from './create.action.js'; -import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; - -const entityActions: Array = [ - { - type: 'entityAction', - kind: 'delete', - alias: 'Umb.EntityAction.RelationType.Delete', - name: 'Delete RelationType Entity Action', - forEntityTypes: [UMB_RELATION_TYPE_ENTITY_TYPE], - meta: { - detailRepositoryAlias: UMB_RELATION_TYPE_REPOSITORY_ALIAS, - itemRepositoryAlias: UMB_RELATION_TYPE_REPOSITORY_ALIAS, - }, - }, - { - type: 'entityAction', - kind: 'default', - alias: 'Umb.EntityAction.RelationType.Create', - name: 'Create RelationType Entity Action', - weight: 900, - api: UmbCreateRelationTypeEntityAction, - forEntityTypes: [UMB_RELATION_TYPE_ROOT_ENTITY_TYPE], - meta: { - icon: 'icon-add', - label: 'Create', - }, - }, -]; - -export const manifests = [...entityActions]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/entity.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/entity.ts index 15a9b9403f..10212498a1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/entity.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/entity.ts @@ -1,2 +1,5 @@ export const UMB_RELATION_TYPE_ROOT_ENTITY_TYPE = 'relation-type-root'; export const UMB_RELATION_TYPE_ENTITY_TYPE = 'relation-type'; + +export type UmbRelationTypeEntityType = typeof UMB_RELATION_TYPE_ENTITY_TYPE; +export type UmbRelationTypeRootEntityType = typeof UMB_RELATION_TYPE_ROOT_ENTITY_TYPE; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/manifests.ts index 3a315095df..5a9178dab2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/manifests.ts @@ -1,13 +1,5 @@ import { manifests as repositoryManifests } from './repository/manifests.js'; -import { manifests as menuManifests } from './menu/manifests.js'; -import { manifests as treeManifests } from './tree/manifests.js'; import { manifests as workspaceManifests } from './workspace/manifests.js'; -import { manifests as entityActionManifests } from './entity-actions/manifests.js'; +import { manifests as collectionManifests } from './collection/manifests.js'; -export const manifests = [ - ...repositoryManifests, - ...menuManifests, - ...treeManifests, - ...workspaceManifests, - ...entityActionManifests, -]; +export const manifests = [...repositoryManifests, ...workspaceManifests, ...collectionManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/menu/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/menu/manifests.ts deleted file mode 100644 index 0caf5e535d..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/menu/manifests.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { UMB_RELATION_TYPE_TREE_ALIAS } from '../tree/index.js'; - -export const manifests = [ - { - type: 'menuItem', - kind: 'tree', - alias: 'Umb.MenuItem.RelationTypes', - name: 'Relation Types Menu Item', - weight: 800, - meta: { - treeAlias: UMB_RELATION_TYPE_TREE_ALIAS, - label: 'Relation Types', - menus: ['Umb.Menu.AdvancedSettings'], - }, - }, - { - type: 'workspaceContext', - name: 'Relation Type Menu Structure Workspace Context', - alias: 'Umb.Context.RelationType.Menu.Structure', - api: () => import('./relation-type-menu-structure.context.js'), - conditions: [ - { - alias: 'Umb.Condition.WorkspaceAlias', - match: 'Umb.Workspace.RelationType', - }, - ], - }, - { - type: 'workspaceFooterApp', - kind: 'menbuBreadcrumb', - alias: 'Umb.WorkspaceFooterApp.RelationType.Breadcrumb', - name: 'Relation Type Breadcrumb Workspace Footer App', - conditions: [ - { - alias: 'Umb.Condition.WorkspaceAlias', - match: 'Umb.Workspace.RelationType', - }, - ], - }, -]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/menu/relation-type-menu-structure.context.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/menu/relation-type-menu-structure.context.ts deleted file mode 100644 index 4a97a4bdcf..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/menu/relation-type-menu-structure.context.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { UMB_RELATION_TYPE_TREE_REPOSITORY_ALIAS } from '../tree/index.js'; -import { UmbMenuTreeStructureWorkspaceContextBase } from '@umbraco-cms/backoffice/menu'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; - -export class UmbRelationTypeMenuStructureWorkspaceContext extends UmbMenuTreeStructureWorkspaceContextBase { - constructor(host: UmbControllerHost) { - super(host, { treeRepositoryAlias: UMB_RELATION_TYPE_TREE_REPOSITORY_ALIAS }); - } -} - -export default UmbRelationTypeMenuStructureWorkspaceContext; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/index.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/index.ts new file mode 100644 index 0000000000..e5e155c2c7 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/index.ts @@ -0,0 +1,2 @@ +export { UmbRelationTypeDetailRepository } from './relation-type-detail.repository.js'; +export { UMB_RELATION_TYPE_DETAIL_REPOSITORY_ALIAS } from './manifests.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/manifests.ts new file mode 100644 index 0000000000..e51460ea80 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/manifests.ts @@ -0,0 +1,21 @@ +import type { ManifestRepository, ManifestStore } from '@umbraco-cms/backoffice/extension-registry'; + +export const UMB_RELATION_TYPE_DETAIL_REPOSITORY_ALIAS = 'Umb.Repository.RelationType.Detail'; + +const repository: ManifestRepository = { + type: 'repository', + alias: UMB_RELATION_TYPE_DETAIL_REPOSITORY_ALIAS, + name: 'Relation Type Detail Repository', + api: () => import('./relation-type-detail.repository.js'), +}; + +export const UMB_RELATION_TYPE_DETAIL_STORE_ALIAS = 'Umb.Store.RelationType.Detail'; + +const store: ManifestStore = { + type: 'store', + alias: UMB_RELATION_TYPE_DETAIL_STORE_ALIAS, + name: 'Relation Type Detail Store', + api: () => import('./relation-type-detail.store.js'), +}; + +export const manifests = [repository, store]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/relation-type-detail.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/relation-type-detail.repository.ts new file mode 100644 index 0000000000..829cbf00ec --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/relation-type-detail.repository.ts @@ -0,0 +1,60 @@ +import type { UmbRelationTypeDetailModel } from '../../types.js'; +import { UmbRelationTypeDetailServerDataSource } from './relation-type-detail.server.data-source.js'; +import { UMB_RELATION_TYPE_DETAIL_STORE_CONTEXT } from './relation-type-detail.store.js'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import type { UmbReadDetailRepository } from '@umbraco-cms/backoffice/repository'; +import { UmbRepositoryBase } from '@umbraco-cms/backoffice/repository'; +import type { UmbDetailStore } from '@umbraco-cms/backoffice/store'; + +// TODO: create read detail repository mixin +export class UmbRelationTypeDetailRepository + extends UmbRepositoryBase + implements UmbReadDetailRepository +{ + #init: Promise; + #detailStore?: UmbDetailStore; + #detailSource = new UmbRelationTypeDetailServerDataSource(this); + + constructor(host: UmbControllerHost) { + super(host); + + this.#init = Promise.all([ + this.consumeContext(UMB_RELATION_TYPE_DETAIL_STORE_CONTEXT, (instance) => { + this.#detailStore = instance; + }).asPromise(), + ]); + } + + /** + * Requests the detail for the given unique + * @param {string} unique + * @return {*} + * @memberof UmbDetailRepositoryBase + */ + async requestByUnique(unique: string) { + if (!unique) throw new Error('Unique is missing'); + await this.#init; + + const { data, error } = await this.#detailSource.read(unique); + + if (data) { + this.#detailStore!.append(data); + } + + return { data, error, asObservable: () => this.#detailStore!.byUnique(unique) }; + } + + /** + * Returns a promise with an observable of the detail for the given unique + * @param {string} unique + * @return {*} + * @memberof UmbDetailRepositoryBase + */ + async byUnique(unique: string) { + if (!unique) throw new Error('Unique is missing'); + await this.#init; + return this.#detailStore!.byUnique(unique); + } +} + +export default UmbRelationTypeDetailRepository; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/relation-type-detail.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/relation-type-detail.server.data-source.ts new file mode 100644 index 0000000000..897b3bdb28 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/relation-type-detail.server.data-source.ts @@ -0,0 +1,72 @@ +import type { UmbRelationTypeDetailModel } from '../../types.js'; +import { UMB_RELATION_TYPE_ENTITY_TYPE } from '../../entity.js'; +import { RelationTypeResource } from '@umbraco-cms/backoffice/external/backend-api'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; +import type { UmbReadDetailDataSource } from '@umbraco-cms/backoffice/repository'; + +/** + * A data source for the Relation Type that fetches data from the server + * @export + * @class UmbRelationTypeServerDataSource + * @implements {RepositoryDetailDataSource} + */ +export class UmbRelationTypeDetailServerDataSource implements UmbReadDetailDataSource { + #host: UmbControllerHost; + + /** + * Creates an instance of UmbRelationTypeServerDataSource. + * @param {UmbControllerHost} host + * @memberof UmbRelationTypeServerDataSource + */ + constructor(host: UmbControllerHost) { + this.#host = host; + } + + /** + * Fetches a Relation Type with the given id from the server + * @param {string} unique + * @return {*} + * @memberof UmbRelationTypeServerDataSource + */ + async read(unique: string) { + if (!unique) throw new Error('Unique is missing'); + + const { data, error } = await tryExecuteAndNotify( + this.#host, + RelationTypeResource.getRelationTypeById({ id: unique }), + ); + + if (error || !data) { + return { error }; + } + + // TODO: make data mapper to prevent errors + const relationType: UmbRelationTypeDetailModel = { + alias: data.alias || '', + child: data.childObject + ? { + objectType: { + unique: data.childObject.id, + name: data.childObject.name || '', + }, + } + : null, + entityType: UMB_RELATION_TYPE_ENTITY_TYPE, + isBidirectional: data.isBidirectional, + isDependency: data.isDependency, + name: data.name, + parent: data.parentObject + ? { + objectType: { + unique: data.parentObject.id, + name: data.parentObject.name || '', + }, + } + : null, + unique: data.id, + }; + + return { data: relationType }; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/relation-type-detail.store.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/relation-type-detail.store.ts new file mode 100644 index 0000000000..87e9eed4b0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/detail/relation-type-detail.store.ts @@ -0,0 +1,27 @@ +import type { UmbRelationTypeDetailModel } from '../../types.js'; +import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; +import { UmbDetailStoreBase } from '@umbraco-cms/backoffice/store'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; + +/** + * @export + * @class UmbRelationTypeDetailStore + * @extends {UmbStoreBase} + * @description - Data Store for RelationType Details + */ +export class UmbRelationTypeDetailStore extends UmbDetailStoreBase { + /** + * Creates an instance of UmbRelationTypeDetailStore. + * @param {UmbControllerHost} host + * @memberof UmbRelationTypeDetailStore + */ + constructor(host: UmbControllerHost) { + super(host, UMB_RELATION_TYPE_DETAIL_STORE_CONTEXT.toString()); + } +} + +export default UmbRelationTypeDetailStore; + +export const UMB_RELATION_TYPE_DETAIL_STORE_CONTEXT = new UmbContextToken( + 'UmbRelationTypeDetailStore', +); diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/index.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/index.ts index e32cef78db..7b266f6eed 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/index.ts @@ -1 +1 @@ -export * from './relation-type.repository.js'; +export * from './detail/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/manifests.ts index cb50bce721..448c479022 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/manifests.ts @@ -1,21 +1,3 @@ -import type { ManifestStore, ManifestRepository } from '@umbraco-cms/backoffice/extension-registry'; +import { manifests as detailManifests } from './detail/manifests.js'; -export const UMB_RELATION_TYPE_REPOSITORY_ALIAS = 'Umb.Repository.RelationType'; - -const repository: ManifestRepository = { - type: 'repository', - alias: UMB_RELATION_TYPE_REPOSITORY_ALIAS, - name: 'Relation Type Repository', - api: () => import('./relation-type.repository.js'), -}; - -export const UMB_RELATION_TYPE_STORE_ALIAS = 'Umb.Store.RelationType'; - -const store: ManifestStore = { - type: 'store', - alias: UMB_RELATION_TYPE_STORE_ALIAS, - name: 'Relation Type Store', - api: () => import('./relation-type.store.js'), -}; - -export const manifests = [repository, store]; +export const manifests = [...detailManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/relation-type.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/relation-type.repository.ts deleted file mode 100644 index 2926b8f742..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/relation-type.repository.ts +++ /dev/null @@ -1,165 +0,0 @@ -import type { UmbRelationTypeTreeStore } from '../tree/index.js'; -import { UMB_RELATION_TYPE_TREE_STORE_CONTEXT } from '../tree/index.js'; -import { UmbRelationTypeServerDataSource } from './sources/relation-type.server.data.js'; -import type { UmbRelationTypeStore } from './relation-type.store.js'; -import { UMB_RELATION_TYPE_STORE_CONTEXT } from './relation-type.store.js'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; -import type { - CreateRelationTypeRequestModel, - UpdateRelationTypeRequestModel, -} from '@umbraco-cms/backoffice/external/backend-api'; -import type { UmbNotificationContext } from '@umbraco-cms/backoffice/notification'; -import { UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification'; -import type { UmbApi } from '@umbraco-cms/backoffice/extension-api'; - -export class UmbRelationTypeRepository extends UmbControllerBase implements UmbApi { - #init!: Promise; - - #treeStore?: UmbRelationTypeTreeStore; - - #detailDataSource: UmbRelationTypeServerDataSource; - #detailStore?: UmbRelationTypeStore; - - #notificationContext?: UmbNotificationContext; - - constructor(host: UmbControllerHost) { - super(host); - - // TODO: figure out how spin up get the correct data source - this.#detailDataSource = new UmbRelationTypeServerDataSource(this._host); - - this.#init = Promise.all([ - this.consumeContext(UMB_RELATION_TYPE_TREE_STORE_CONTEXT, (instance) => { - this.#treeStore = instance; - }).asPromise(), - - this.consumeContext(UMB_RELATION_TYPE_STORE_CONTEXT, (instance) => { - this.#detailStore = instance; - }).asPromise(), - - this.consumeContext(UMB_NOTIFICATION_CONTEXT, (instance) => { - this.#notificationContext = instance; - }).asPromise(), - ]); - } - - // TODO: Trash - // TODO: Move - - // DETAILS: - - async createScaffold() { - return this.#detailDataSource.createScaffold(null); - } - - async requestRelationsById(id: string) { - await this.#init; - - // TODO: should we show a notification if the id is missing? - // Investigate what is best for Acceptance testing, cause in that perspective a thrown error might be the best choice? - if (!id) { - throw new Error('Id is missing'); - } - - const { data, error } = await this.#detailDataSource.readRelations(id); - - return { data, error }; - } - - async requestById(id: string) { - await this.#init; - - // TODO: should we show a notification if the id is missing? - // Investigate what is best for Acceptance testing, cause in that perspective a thrown error might be the best choice? - if (!id) { - throw new Error('Id is missing'); - } - - const { data, error } = await this.#detailDataSource.read(id); - - if (data) { - this.#detailStore?.append(data); - } - - return { data, error }; - } - - async byId(id: string) { - await this.#init; - return this.#detailStore!.byId(id); - } - - // Could potentially be general methods: - - async create(template: CreateRelationTypeRequestModel) { - if (!template) throw new Error('Template is missing'); - if (!template.id) throw new Error('Template id is missing'); - - await this.#init; - - const { error } = await this.#detailDataSource.create(template); - - if (!error) { - // TODO: we currently don't use the detail store for anything. - // Consider to look up the data before fetching from the server - // TODO: Update tree store with the new item? or ask tree to request the new item? - // this.#detailStore?.append(template); - - const notification = { data: { message: `Relation Type created` } }; - this.#notificationContext?.peek('positive', notification); - } - - return { error }; - } - - async save(id: string, item: UpdateRelationTypeRequestModel) { - if (!id) throw new Error('Id is missing'); - if (!item) throw new Error('Relation type is missing'); - - await this.#init; - - const { error } = await this.#detailDataSource.update(id, item); - - if (!error) { - // TODO: we currently don't use the detail store for anything. - // Consider to look up the data before fetching from the server - // Consider notify a workspace if a template is updated in the store while someone is editing it. - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - this.#detailStore?.append(item); - this.#treeStore?.updateItem(id, { name: item.name }); - - const notification = { data: { message: `Relation Type saved` } }; - this.#notificationContext?.peek('positive', notification); - } - - return { error }; - } - - // General: - - async delete(id: string) { - if (!id) throw new Error('Id is missing'); - - await this.#init; - - const { error } = await this.#detailDataSource.delete(id); - - if (!error) { - // TODO: we currently don't use the detail store for anything. - // Consider to look up the data before fetching from the server. - // Consider notify a workspace if a template is deleted from the store while someone is editing it. - - this.#detailStore?.removeItem(id); - this.#treeStore?.removeItem(id); - - const notification = { data: { message: `Relation Type deleted` } }; - this.#notificationContext?.peek('positive', notification); - } - - return { error }; - } -} - -export default UmbRelationTypeRepository; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/relation-type.store.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/relation-type.store.ts deleted file mode 100644 index 535cd3acc7..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/relation-type.store.ts +++ /dev/null @@ -1,57 +0,0 @@ -import type { RelationTypeResponseModel } from '@umbraco-cms/backoffice/external/backend-api'; -import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; -import { UmbStoreBase } from '@umbraco-cms/backoffice/store'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; - -export const UMB_RELATION_TYPE_STORE_CONTEXT = new UmbContextToken('UmbRelationTypeStore'); - -/** - * @export - * @class UmbRelationTypeStore - * @extends {UmbStoreBase} - * @description - Data Store for Template Details - */ -export class UmbRelationTypeStore extends UmbStoreBase { - /** - * Creates an instance of UmbRelationTypeStore. - * @param {UmbControllerHost} host - * @memberof UmbRelationTypeStore - */ - constructor(host: UmbControllerHost) { - super( - host, - UMB_RELATION_TYPE_STORE_CONTEXT.toString(), - new UmbArrayState([], (x) => x.id), - ); - } - - /** - * Append a relation-type to the store - * @param {RelationTypeResponseModel} RelationType - * @memberof UmbRelationTypeStore - */ - append(RelationType: RelationTypeResponseModel) { - this._data.append([RelationType]); - } - - /** - * Append a relation-type to the store - * @param {id} RelationTypeResponseModel id. - * @memberof UmbRelationTypeStore - */ - byId(id: RelationTypeResponseModel['id']) { - return this._data.asObservablePart((x) => x.find((y) => y.id === id)); - } - - /** - * Removes relation-types in the store with the given uniques - * @param {string[]} uniques - * @memberof UmbRelationTypeStore - */ - remove(uniques: Array) { - this._data.remove(uniques); - } -} - -export default UmbRelationTypeStore; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/sources/relation-type.server.data.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/sources/relation-type.server.data.ts deleted file mode 100644 index 88bfe5c358..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/repository/sources/relation-type.server.data.ts +++ /dev/null @@ -1,140 +0,0 @@ -import type { - RelationTypeResponseModel, - CreateRelationTypeRequestModel, - UpdateRelationTypeRequestModel, -} from '@umbraco-cms/backoffice/external/backend-api'; -import { RelationTypeResource, RelationResource } from '@umbraco-cms/backoffice/external/backend-api'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; -import { UmbId } from '@umbraco-cms/backoffice/id'; - -/** - * A data source for the Relation Type that fetches data from the server - * @export - * @class UmbRelationTypeServerDataSource - * @implements {RepositoryDetailDataSource} - */ -export class UmbRelationTypeServerDataSource { - #host: UmbControllerHost; - - /** - * Creates an instance of UmbRelationTypeServerDataSource. - * @param {UmbControllerHost} host - * @memberof UmbRelationTypeServerDataSource - */ - constructor(host: UmbControllerHost) { - this.#host = host; - } - - /** - * Fetches a Relation Type with the given id from the server - * @param {string} id - * @return {*} - * @memberof UmbRelationTypeServerDataSource - */ - async read(id: string) { - if (!id) { - throw new Error('Id is missing'); - } - - return tryExecuteAndNotify( - this.#host, - RelationTypeResource.getRelationTypeById({ - id, - }), - ); - } - - /** - * Fetches a Relation Type with the given id from the server - * @param {string} id - * @return {*} - * @memberof UmbRelationTypeServerDataSource - */ - async readRelations(id: string) { - if (!id) { - throw new Error('Id is missing'); - } - - return tryExecuteAndNotify( - this.#host, - RelationResource.getRelationTypeById({ - id, - }), - ); - } - - /** - * Creates a new Relation Type scaffold - * @param {(string | null)} parentId - * @return {*} - * @memberof UmbRelationTypeServerDataSource - */ - async createScaffold(parentId: string | null) { - const data: RelationTypeResponseModel = { - id: UmbId.new(), - name: '', - alias: '', - isBidirectional: false, - isDependency: false, - path: '', - isDeletable: false, - }; - - return { data }; - } - - /** - * Inserts a new Relation Type on the server - * @param {Document} relationType - * @return {*} - * @memberof UmbRelationTypeServerDataSource - */ - async create(relationType: CreateRelationTypeRequestModel) { - if (!relationType.id) throw new Error('RelationType id is missing'); - - return tryExecuteAndNotify( - this.#host, - RelationTypeResource.postRelationType({ - requestBody: relationType, - }), - ); - } - - /** - * Updates a RelationType on the server - * @param {RelationTypeResponseModel} relationType - * @return {*} - * @memberof UmbRelationTypeServerDataSource - */ - async update(id: string, relationType: UpdateRelationTypeRequestModel) { - if (!id) throw new Error('RelationType id is missing'); - - return tryExecuteAndNotify( - this.#host, - RelationTypeResource.putRelationTypeById({ - id, - requestBody: relationType, - }), - ); - } - - /** - * Deletes a Relation Type on the server - * @param {string} id - * @return {*} - * @memberof UmbRelationTypeServerDataSource - */ - async delete(id: string) { - if (!id) { - throw new Error('RelationType id is missing'); - } - - return tryExecuteAndNotify( - this.#host, - RelationTypeResource.deleteRelationTypeById({ - id, - }), - ); - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/index.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/index.ts deleted file mode 100644 index 0d559dcc36..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export { UmbRelationTypeTreeRepository } from './relation-type-tree.repository.js'; -export { - UMB_RELATION_TYPE_TREE_REPOSITORY_ALIAS, - UMB_RELATION_TYPE_TREE_STORE_ALIAS, - UMB_RELATION_TYPE_TREE_ALIAS, -} from './manifests.js'; -export { UMB_RELATION_TYPE_TREE_STORE_CONTEXT } from './relation-type-tree.store.js'; -export { type UmbRelationTypeTreeStore } from './relation-type-tree.store.js'; -export * from './types.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/manifests.ts deleted file mode 100644 index 1d293d6455..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/manifests.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { UMB_RELATION_TYPE_ENTITY_TYPE, UMB_RELATION_TYPE_ROOT_ENTITY_TYPE } from '../entity.js'; -import { manifests as reloadTreeItemChildrenManifest } from './reload-tree-item-children/manifests.js'; -import type { - ManifestRepository, - ManifestTree, - ManifestTreeItem, - ManifestTreeStore, -} from '@umbraco-cms/backoffice/extension-registry'; - -export const UMB_RELATION_TYPE_TREE_REPOSITORY_ALIAS = 'Umb.Repository.RelationType.Tree'; -export const UMB_RELATION_TYPE_TREE_STORE_ALIAS = 'Umb.Store.RelationType.Tree'; -export const UMB_RELATION_TYPE_TREE_ALIAS = 'Umb.Tree.RelationType'; - -const treeRepository: ManifestRepository = { - type: 'repository', - alias: UMB_RELATION_TYPE_TREE_REPOSITORY_ALIAS, - name: 'Relation Type Tree Repository', - api: () => import('./relation-type-tree.repository.js'), -}; - -const treeStore: ManifestTreeStore = { - type: 'treeStore', - alias: UMB_RELATION_TYPE_TREE_STORE_ALIAS, - name: 'Relation Type Tree Store', - api: () => import('./relation-type-tree.store.js'), -}; - -const tree: ManifestTree = { - type: 'tree', - kind: 'default', - alias: UMB_RELATION_TYPE_TREE_ALIAS, - name: 'Relation Type Tree', - meta: { - repositoryAlias: UMB_RELATION_TYPE_TREE_REPOSITORY_ALIAS, - }, -}; - -const treeItem: ManifestTreeItem = { - type: 'treeItem', - kind: 'default', - alias: 'Umb.TreeItem.RelationType', - name: 'RelationType Tree Item', - forEntityTypes: [UMB_RELATION_TYPE_ROOT_ENTITY_TYPE, UMB_RELATION_TYPE_ENTITY_TYPE], -}; - -export const manifests = [treeRepository, treeStore, tree, treeItem, ...reloadTreeItemChildrenManifest]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/relation-type-tree.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/relation-type-tree.repository.ts deleted file mode 100644 index 73a740484e..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/relation-type-tree.repository.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { UMB_RELATION_TYPE_ROOT_ENTITY_TYPE } from '../entity.js'; -import { UmbRelationTypeTreeServerDataSource } from './relation-type-tree.server.data-source.js'; -import type { UmbRelationTypeTreeItemModel, UmbRelationTypeTreeRootModel } from './types.js'; -import { UMB_RELATION_TYPE_TREE_STORE_CONTEXT } from './relation-type-tree.store.js'; -import { UmbTreeRepositoryBase } from '@umbraco-cms/backoffice/tree'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import type { UmbApi } from '@umbraco-cms/backoffice/extension-api'; - -export class UmbRelationTypeTreeRepository - extends UmbTreeRepositoryBase - implements UmbApi -{ - constructor(host: UmbControllerHost) { - super(host, UmbRelationTypeTreeServerDataSource, UMB_RELATION_TYPE_TREE_STORE_CONTEXT); - } - - async requestTreeRoot() { - const data = { - unique: null, - entityType: UMB_RELATION_TYPE_ROOT_ENTITY_TYPE, - name: 'Relation Types', - hasChildren: true, - isContainer: false, - isFolder: true, - }; - - return { data }; - } -} - -export default UmbRelationTypeTreeRepository; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/relation-type-tree.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/relation-type-tree.server.data-source.ts deleted file mode 100644 index 4a176d8092..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/relation-type-tree.server.data-source.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { UmbRelationTypeTreeItemModel } from './types.js'; -import type { NamedEntityTreeItemResponseModel } from '@umbraco-cms/backoffice/external/backend-api'; -import { RelationTypeResource } from '@umbraco-cms/backoffice/external/backend-api'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import type { UmbTreeChildrenOfRequestArgs, UmbTreeRootItemsRequestArgs } from '@umbraco-cms/backoffice/tree'; -import { UmbTreeServerDataSourceBase } from '@umbraco-cms/backoffice/tree'; - -/** - * A data source for the Relation Type tree that fetches data from the server - * @export - * @class UmbRelationTypeTreeServerDataSource - * @implements {UmbTreeDataSource} - */ -export class UmbRelationTypeTreeServerDataSource extends UmbTreeServerDataSourceBase< - NamedEntityTreeItemResponseModel, - UmbRelationTypeTreeItemModel -> { - /** - * Creates an instance of UmbRelationTypeTreeServerDataSource. - * @param {UmbControllerHost} host - * @memberof UmbRelationTypeTreeServerDataSource - */ - constructor(host: UmbControllerHost) { - super(host, { - getRootItems, - getChildrenOf, - getAncestorsOf, - mapper, - }); - } -} - -const getRootItems = (args: UmbTreeRootItemsRequestArgs) => - // eslint-disable-next-line local-rules/no-direct-api-import - RelationTypeResource.getTreeRelationTypeRoot({ skip: args.skip, take: args.take }); - -const getChildrenOf = (args: UmbTreeChildrenOfRequestArgs) => { - if (args.parentUnique === null) { - return getRootItems(args); - } else { - throw new Error('Not supported for the relation type tree'); - } -}; - -const getAncestorsOf = () => { - throw new Error('Not supported for the relation type tree'); -}; - -const mapper = (item: NamedEntityTreeItemResponseModel): UmbRelationTypeTreeItemModel => { - return { - unique: item.id, - parentUnique: item.parent ? item.parent.id : null, - name: item.name, - entityType: 'relation-type', - hasChildren: item.hasChildren, - isFolder: false, - }; -}; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/relation-type-tree.store.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/relation-type-tree.store.ts deleted file mode 100644 index 34a19c035a..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/relation-type-tree.store.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UmbUniqueTreeStore } from '@umbraco-cms/backoffice/tree'; - -/** - * @export - * @class UmbRelationTypeTreeStore - * @extends {UmbStoreBase} - * @description - Tree Data Store for Relation Type Items - */ -export class UmbRelationTypeTreeStore extends UmbUniqueTreeStore { - /** - * Creates an instance of UmbRelationTypeTreeStore. - * @param {UmbControllerHost} host - * @memberof UmbRelationTypeTreeStore - */ - constructor(host: UmbControllerHost) { - super(host, UMB_RELATION_TYPE_TREE_STORE_CONTEXT.toString()); - } -} - -export default UmbRelationTypeTreeStore; - -export const UMB_RELATION_TYPE_TREE_STORE_CONTEXT = new UmbContextToken( - 'UmbRelationTypeTreeStore', -); diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/reload-tree-item-children/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/reload-tree-item-children/manifests.ts deleted file mode 100644 index dc6d18eaf3..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/reload-tree-item-children/manifests.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { UMB_RELATION_TYPE_ROOT_ENTITY_TYPE } from '../../entity.js'; -import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry'; - -export const manifests: Array = [ - { - type: 'entityAction', - kind: 'reloadTreeItemChildren', - alias: 'Umb.EntityAction.RelationType.Tree.ReloadChildrenOf', - name: 'Reload Relation Type Tree Item Children Entity Action', - forEntityTypes: [UMB_RELATION_TYPE_ROOT_ENTITY_TYPE], - }, -]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/types.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/types.ts deleted file mode 100644 index 3434831888..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/tree/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -import type { UmbUniqueTreeItemModel, UmbUniqueTreeRootModel } from '@umbraco-cms/backoffice/tree'; - -export interface UmbRelationTypeTreeItemModel extends UmbUniqueTreeItemModel {} -export interface UmbRelationTypeTreeRootModel extends UmbUniqueTreeRootModel {} diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/types.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/types.ts new file mode 100644 index 0000000000..a24447d740 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/types.ts @@ -0,0 +1,22 @@ +import type { UmbRelationTypeEntityType } from './entity.js'; + +export interface UmbRelationTypeDetailModel { + alias: string; + child: { + objectType: { + unique: string; + name: string; + }; + } | null; + entityType: UmbRelationTypeEntityType; + isBidirectional: boolean; + isDependency: boolean; + name: string; + parent: { + objectType: { + unique: string; + name: string; + }; + } | null; + unique: string; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/manifests.ts index d2d2eebef5..974f0306a2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/manifests.ts @@ -1,79 +1,4 @@ -import { UmbSaveWorkspaceAction } from '@umbraco-cms/backoffice/workspace'; -import type { - ManifestWorkspaces, - ManifestWorkspaceActions, - ManifestWorkspaceView, -} from '@umbraco-cms/backoffice/extension-registry'; +import { manifests as relationTypeManifests } from './relation-type/manifests.js'; +import { manifests as relationTypeRootManifests } from './relation-type-root/manifests.js'; -const workspace: ManifestWorkspaces = { - type: 'workspace', - kind: 'routable', - alias: 'Umb.Workspace.RelationType', - name: 'Relation Type Workspace', - api: () => import('./relation-type-workspace.context.js'), - meta: { - entityType: 'relation-type', - }, -}; - -const workspaceViews: Array = [ - { - type: 'workspaceView', - alias: 'Umb.WorkspaceView.RelationType.RelationType', - name: 'Relation Type Workspace RelationType View', - js: () => import('./views/relation-type/relation-type-workspace-view-relation-type.element.js'), - weight: 20, - meta: { - label: 'RelationType', - pathname: 'relation-type', - icon: 'icon-info', - }, - conditions: [ - { - alias: 'Umb.Condition.WorkspaceAlias', - match: workspace.alias, - }, - ], - }, - { - type: 'workspaceView', - alias: 'Umb.WorkspaceView.RelationType.Relation', - name: 'Relation Type Workspace Relation View', - js: () => import('./views/relation/workspace-view-relation-type-relation.element.js'), - weight: 10, - meta: { - label: 'Relation', - pathname: 'relation', - icon: 'icon-trafic', - }, - conditions: [ - { - alias: 'Umb.Condition.WorkspaceAlias', - match: workspace.alias, - }, - ], - }, -]; - -const workspaceActions: Array = [ - { - type: 'workspaceAction', - kind: 'default', - alias: 'Umb.WorkspaceAction.RelationType.Save', - name: 'Save Relation Type Workspace Action', - api: UmbSaveWorkspaceAction, - meta: { - label: 'Save', - look: 'primary', - color: 'positive', - }, - conditions: [ - { - alias: 'Umb.Condition.WorkspaceAlias', - match: workspace.alias, - }, - ], - }, -]; - -export const manifests = [workspace, ...workspaceViews, ...workspaceActions]; +export const manifests = [...relationTypeManifests, ...relationTypeRootManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type-root/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type-root/manifests.ts new file mode 100644 index 0000000000..8466bfc97f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type-root/manifests.ts @@ -0,0 +1,13 @@ +import type { ManifestWorkspace } from '@umbraco-cms/backoffice/extension-registry'; + +const workspace: ManifestWorkspace = { + type: 'workspace', + alias: 'Umb.Workspace.RelationTypeRoot', + name: 'Relation Type Root Workspace', + element: () => import('./relation-type-root-workspace.element.js'), + meta: { + entityType: 'relation-type-root', + }, +}; + +export const manifests = [workspace]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type-root/relation-type-root-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type-root/relation-type-root-workspace.element.ts new file mode 100644 index 0000000000..61b0e50365 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type-root/relation-type-root-workspace.element.ts @@ -0,0 +1,20 @@ +import { UMB_RELATION_TYPE_COLLECTION_ALIAS } from '../../collection/index.js'; +import { html, customElement } from '@umbraco-cms/backoffice/external/lit'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; + +@customElement('umb-relation-type-root-workspace') +export class UmbRelationTypeRootWorkspaceElement extends UmbLitElement { + render() { + return html` + ; + `; + } +} + +export { UmbRelationTypeRootWorkspaceElement as element }; + +declare global { + interface HTMLElementTagNameMap { + 'umb-relation-type-root-workspace': UmbRelationTypeRootWorkspaceElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type-workspace.context.ts deleted file mode 100644 index 0319266191..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type-workspace.context.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { UmbRelationTypeRepository } from '../repository/relation-type.repository.js'; -import { UmbRelationTypeWorkspaceEditorElement } from './relation-type-workspace-editor.element.js'; -import { - type UmbSaveableWorkspaceContext, - UmbSaveableWorkspaceContextBase, - type UmbRoutableWorkspaceContext, - UmbWorkspaceRouteManager, - UmbWorkspaceIsNewRedirectController, -} from '@umbraco-cms/backoffice/workspace'; -import type { RelationTypeBaseModel, RelationTypeResponseModel } from '@umbraco-cms/backoffice/external/backend-api'; -import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; - -export class UmbRelationTypeWorkspaceContext - extends UmbSaveableWorkspaceContextBase - implements UmbSaveableWorkspaceContext, UmbRoutableWorkspaceContext -{ - // - public readonly repository: UmbRelationTypeRepository = new UmbRelationTypeRepository(this); - - #parent = new UmbObjectState<{ entityType: string; unique: string | null } | undefined>(undefined); - readonly parentUnique = this.#parent.asObservablePart((parent) => (parent ? parent.unique : undefined)); - - #data = new UmbObjectState(undefined); - readonly data = this.#data.asObservable(); - readonly unique = this.#data.asObservablePart((data) => data?.id); - readonly name = this.#data.asObservablePart((data) => data?.name); - readonly id = this.#data.asObservablePart((data) => data?.id); - - readonly routes = new UmbWorkspaceRouteManager(this); - - constructor(host: UmbControllerHost) { - super(host, 'Umb.Workspace.RelationType'); - - this.routes.setRoutes([ - { - path: 'create/parent/:entityType/:parentUnique', - component: UmbRelationTypeWorkspaceEditorElement, - setup: (_component, info) => { - const parentEntityType = info.match.params.entityType; - const parentUnique = info.match.params.parentUnique === 'null' ? null : info.match.params.parentUnique; - this.create({ entityType: parentEntityType, unique: parentUnique }); - - new UmbWorkspaceIsNewRedirectController( - this, - this, - this.getHostElement().shadowRoot!.querySelector('umb-router-slot')!, - ); - }, - }, - { - path: 'edit/:unique', - component: UmbRelationTypeWorkspaceEditorElement, - setup: (_component, info) => { - const unique = info.match.params.unique; - this.load(unique); - }, - }, - ]); - } - - protected resetState(): void { - super.resetState(); - this.#data.setValue(undefined); - } - - async load(id: string) { - this.resetState(); - const { data } = await this.repository.requestById(id); - - if (data) { - this.setIsNew(false); - this.#data.update(data); - } - } - - async create(parent: { entityType: string; unique: string | null }) { - this.resetState(); - this.#parent.setValue(parent); - const { data } = await this.repository.createScaffold(); - if (!data) return; - this.setIsNew(true); - this.#data.setValue(data); - } - - async getRelations() { - //TODO: How do we test this? - return await this.repository.requestRelationsById(this.getUnique()); - } - - getData() { - return this.#data.getValue(); - } - - getUnique() { - return this.getData()?.id || ''; - } - - getEntityType() { - return 'relation-type'; - } - - setName(name: string) { - this.#data.update({ name }); - } - - async save() { - if (!this.#data.value) return; - if (!this.#data.value.id) return; - - let response = undefined; - - if (this.getIsNew()) { - response = await this.repository.create(this.#data.value); - } else { - response = await this.repository.save(this.#data.value.id, this.#data.value); - } - - if (response.error) return; - - // If it went well, then its not new anymore?. - this.setIsNew(false); - } - - update(id: K, value: RelationTypeBaseModel[K]) { - this.#data.update({ [id]: value }); - } - - async delete(id: string) { - await this.repository.delete(id); - } - - public destroy(): void { - this.#data.destroy(); - super.destroy(); - } -} - -export { UmbRelationTypeWorkspaceContext as api }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type/manifests.ts new file mode 100644 index 0000000000..49fc7fad40 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type/manifests.ts @@ -0,0 +1,35 @@ +import type { ManifestWorkspaces, ManifestWorkspaceView } from '@umbraco-cms/backoffice/extension-registry'; + +const workspace: ManifestWorkspaces = { + type: 'workspace', + kind: 'routable', + alias: 'Umb.Workspace.RelationType', + name: 'Relation Type Workspace', + api: () => import('./relation-type-workspace.context.js'), + meta: { + entityType: 'relation-type', + }, +}; + +const workspaceViews: Array = [ + { + type: 'workspaceView', + alias: 'Umb.WorkspaceView.RelationType.Details', + name: 'Relation Type Details Workspace View', + js: () => import('./views/relation-type-detail-workspace-view.element.js'), + weight: 20, + meta: { + label: 'Details', + pathname: 'details', + icon: 'icon-trafic', + }, + conditions: [ + { + alias: 'Umb.Condition.WorkspaceAlias', + match: workspace.alias, + }, + ], + }, +]; + +export const manifests = [workspace, ...workspaceViews]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type/relation-type-workspace-editor.element.ts similarity index 62% rename from src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type-workspace-editor.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type/relation-type-workspace-editor.element.ts index e08934199b..888a0908e0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type/relation-type-workspace-editor.element.ts @@ -1,9 +1,8 @@ import { UMB_RELATION_TYPE_WORKSPACE_CONTEXT } from './relation-type-workspace.context-token.js'; -import type { UUIInputElement } from '@umbraco-cms/backoffice/external/uui'; -import { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui'; +import { observeMultiple } from '@umbraco-cms/backoffice/observable-api'; import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import type { RelationTypeResponseModel } from '@umbraco-cms/backoffice/external/backend-api'; + /** * @element umb-relation-type-workspace-editor * @description - Element for displaying a Relation Type Workspace @@ -13,7 +12,10 @@ export class UmbRelationTypeWorkspaceEditorElement extends UmbLitElement { #workspaceContext?: typeof UMB_RELATION_TYPE_WORKSPACE_CONTEXT.TYPE; @state() - private _relationType?: RelationTypeResponseModel; + private _name?: string = ''; + + @state() + private _alias?: string = ''; constructor() { super(); @@ -26,26 +28,18 @@ export class UmbRelationTypeWorkspaceEditorElement extends UmbLitElement { #observeRelationType() { if (!this.#workspaceContext) return; - this.observe(this.#workspaceContext.data, (data) => (this._relationType = data)); - } - - // TODO. find a way where we don't have to do this for all workspaces. - private _handleInput(event: UUIInputEvent) { - if (event instanceof UUIInputEvent) { - const target = event.composedPath()[0] as UUIInputElement; - - if (typeof target?.value === 'string') { - this.#workspaceContext?.setName(target.value); - } - } + this.observe(observeMultiple([this.#workspaceContext.name, this.#workspaceContext.alias]), ([name, alias]) => { + this._name = name; + this._alias = alias; + }); } render() { return html` @@ -63,7 +57,6 @@ export class UmbRelationTypeWorkspaceEditorElement extends UmbLitElement { #header { display: flex; flex: 1 1 auto; - margin: 0 var(--uui-size-layout-1); } #name { diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type-workspace.context-token.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type/relation-type-workspace.context-token.ts similarity index 69% rename from src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type-workspace.context-token.ts rename to src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type/relation-type-workspace.context-token.ts index 2fcb61a826..e2e882f0a4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type-workspace.context-token.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type/relation-type-workspace.context-token.ts @@ -1,11 +1,8 @@ import type { UmbRelationTypeWorkspaceContext } from './relation-type-workspace.context.js'; import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; -import type { UmbSaveableWorkspaceContext } from '@umbraco-cms/backoffice/workspace'; -export const UMB_RELATION_TYPE_WORKSPACE_CONTEXT = new UmbContextToken< - UmbSaveableWorkspaceContext, - UmbRelationTypeWorkspaceContext ->( +// TODO: Make readonly workspace context type +export const UMB_RELATION_TYPE_WORKSPACE_CONTEXT = new UmbContextToken( 'UmbWorkspaceContext', undefined, (context): context is UmbRelationTypeWorkspaceContext => context.getEntityType?.() === 'relation-type', diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type/relation-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type/relation-type-workspace.context.ts new file mode 100644 index 0000000000..a1eef80164 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type/relation-type-workspace.context.ts @@ -0,0 +1,68 @@ +import { UmbRelationTypeDetailRepository } from '../../repository/detail/index.js'; +import type { UmbRelationTypeDetailModel } from '../../types.js'; +import { UmbRelationTypeWorkspaceEditorElement } from './relation-type-workspace-editor.element.js'; +import { UMB_RELATION_TYPE_WORKSPACE_CONTEXT } from './relation-type-workspace.context-token.js'; +import { UmbWorkspaceRouteManager } from '@umbraco-cms/backoffice/workspace'; +import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; + +export class UmbRelationTypeWorkspaceContext extends UmbContextBase { + public readonly workspaceAlias = 'Umb.Workspace.RelationType'; + public readonly repository = new UmbRelationTypeDetailRepository(this); + + #data = new UmbObjectState(undefined); + readonly data = this.#data.asObservable(); + + readonly unique = this.#data.asObservablePart((data) => data?.unique); + readonly name = this.#data.asObservablePart((data) => data?.name); + readonly alias = this.#data.asObservablePart((data) => data?.alias); + readonly parent = this.#data.asObservablePart((data) => data?.parent); + readonly child = this.#data.asObservablePart((data) => data?.child); + readonly isBidirectional = this.#data.asObservablePart((data) => data?.isBidirectional); + readonly isDependency = this.#data.asObservablePart((data) => data?.isDependency); + + readonly routes = new UmbWorkspaceRouteManager(this); + + constructor(host: UmbControllerHost) { + super(host, UMB_RELATION_TYPE_WORKSPACE_CONTEXT); + + this.routes.setRoutes([ + { + path: 'edit/:unique', + component: UmbRelationTypeWorkspaceEditorElement, + setup: (_component, info) => { + const unique = info.match.params.unique; + this.load(unique); + }, + }, + ]); + } + + async load(unique: string) { + const { data } = await this.repository.requestByUnique(unique); + + if (data) { + this.#data.setValue(data); + } + } + + getData() { + return this.#data.getValue(); + } + + getUnique() { + return this.getData()?.unique; + } + + getEntityType() { + return 'relation-type'; + } + + public destroy(): void { + this.#data.destroy(); + super.destroy(); + } +} + +export { UmbRelationTypeWorkspaceContext as api }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type/views/relation-type-detail-workspace-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type/views/relation-type-detail-workspace-view.element.ts new file mode 100644 index 0000000000..78c3003a55 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/relation-type/views/relation-type-detail-workspace-view.element.ts @@ -0,0 +1,226 @@ +import { UMB_RELATION_TYPE_WORKSPACE_CONTEXT } from '../relation-type-workspace.context-token.js'; +import type { UmbRelationTypeDetailModel } from '../../../types.js'; +import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; +import { css, html, customElement, state, nothing } from '@umbraco-cms/backoffice/external/lit'; +import type { UmbTableColumn, UmbTableConfig, UmbTableItem } from '@umbraco-cms/backoffice/components'; +import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry'; +import type { UmbRelationDetailModel } from '@umbraco-cms/backoffice/relations'; +import { UmbRelationCollectionRepository } from '@umbraco-cms/backoffice/relations'; +import { observeMultiple } from '@umbraco-cms/backoffice/observable-api'; +import { UmbPaginationManager } from '@umbraco-cms/backoffice/utils'; +import type { UUIPaginationEvent } from '@umbraco-cms/backoffice/external/uui'; + +@customElement('umb-relation-type-detail-workspace-view') +export class UmbRelationTypeDetailWorkspaceViewElement extends UmbLitElement implements UmbWorkspaceViewElement { + @state() + _relations: Array = []; + + @state() + _parent?: UmbRelationTypeDetailModel['parent']; + + @state() + _child?: UmbRelationTypeDetailModel['child']; + + @state() + _isBidirectional?: UmbRelationTypeDetailModel['isBidirectional']; + + @state() + _isDependency?: UmbRelationTypeDetailModel['isDependency']; + + @state() + _currentPageNumber = 1; + + @state() + _totalPages = 1; + + #workspaceContext?: typeof UMB_RELATION_TYPE_WORKSPACE_CONTEXT.TYPE; + #relationCollectionRepository = new UmbRelationCollectionRepository(this); + #paginationManager = new UmbPaginationManager(); + + constructor() { + super(); + + this.#paginationManager.setPageSize(50); + + this.observe(this.#paginationManager.currentPage, (number) => (this._currentPageNumber = number)); + this.observe(this.#paginationManager.totalPages, (number) => (this._totalPages = number)); + + this.#paginationManager.addEventListener('change', () => {}); + + this.consumeContext(UMB_RELATION_TYPE_WORKSPACE_CONTEXT, (instance) => { + this.#workspaceContext = instance; + this.#requestRelations(); + this.#observeDetails(); + }); + } + + #observeDetails() { + if (!this.#workspaceContext) return; + + this.observe( + observeMultiple([ + this.#workspaceContext.parent, + this.#workspaceContext.child, + this.#workspaceContext.isBidirectional, + this.#workspaceContext.isDependency, + ]), + ([parent, child, isBidirectional, isDependency]) => { + this._parent = parent; + this._child = child; + this._isBidirectional = isBidirectional; + this._isDependency = isDependency; + }, + ); + } + + async #requestRelations() { + const relationTypeUnique = this.#workspaceContext?.getUnique(); + if (!relationTypeUnique) throw new Error('Relation type unique is required'); + + const { data } = await this.#relationCollectionRepository.requestCollection({ + relationType: { + unique: relationTypeUnique, + }, + skip: this.#paginationManager.getSkip(), + take: this.#paginationManager.getPageSize(), + }); + + if (data) { + this._relations = data.items; + this.#paginationManager.setTotalItems(data.total); + } + } + + private _tableConfig: UmbTableConfig = { + allowSelection: false, + hideIcon: true, + }; + + private _tableColumns: Array = [ + { + name: 'Parent', + alias: 'parent', + }, + { + name: 'Child', + alias: 'child', + }, + { + name: 'Created', + alias: 'created', + }, + { + name: 'Comment', + alias: 'comment', + }, + ]; + + private get _tableItems(): UmbTableItem[] { + if (this._relations.length === 0) { + return [ + { + id: 'no-relations', + data: [ + { + columnAlias: 'parent', + value: 'No relations found', + }, + ], + }, + ]; + } + + return this._relations.map((relation) => { + return { + id: relation.unique, + data: [ + { + columnAlias: 'parent', + value: relation.parent.name, + }, + { + columnAlias: 'child', + value: relation.child.name, + }, + { + columnAlias: 'created', + value: this.localize.date(relation.createDate, { dateStyle: 'long', timeStyle: 'medium' }), + }, + { + columnAlias: 'comment', + value: relation.comment, + }, + ], + }; + }); + } + + #onPageChange(event: UUIPaginationEvent) { + this.#paginationManager.setCurrentPageNumber(event.target?.current); + this.#requestRelations(); + } + + render() { + return html`${this.#renderRelations()}${this.#renderDetails()}`; + } + + #renderRelations() { + return html` +
+ + + ${this._totalPages > 1 + ? html` + + ` + : nothing} +
+ `; + } + + #renderDetails() { + return html` +
${this._parent?.objectType.name}
+
+ +
${this._child?.objectType.name}
+
+ +
${this._isBidirectional}
+
+ +
${this._isDependency}
+
+
`; + } + + static styles = [ + UmbTextStyles, + css` + :host { + display: grid; + gap: var(--uui-size-layout-1); + padding: var(--uui-size-layout-1); + grid-template-columns: 1fr 350px; + } + + uui-pagination { + margin-top: var(--uui-size-layout-1); + display: block; + } + `, + ]; +} + +export default UmbRelationTypeDetailWorkspaceViewElement; + +declare global { + interface HTMLElementTagNameMap { + 'umb-relation-type-detail-workspace-view': UmbRelationTypeDetailWorkspaceViewElement; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/views/relation-type/relation-type-workspace-view-relation-type.element.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/views/relation-type/relation-type-workspace-view-relation-type.element.ts deleted file mode 100644 index 003ecc89a6..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/views/relation-type/relation-type-workspace-view-relation-type.element.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { UMB_RELATION_TYPE_WORKSPACE_CONTEXT } from '../../relation-type-workspace.context-token.js'; -import type { - UUIBooleanInputEvent, - UUIRadioGroupElement, - UUIRadioGroupEvent, - UUISelectEvent, - UUIToggleElement, -} from '@umbraco-cms/backoffice/external/uui'; -import { css, html, customElement, state, ifDefined } from '@umbraco-cms/backoffice/external/lit'; -import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import type { RelationTypeResponseModel } from '@umbraco-cms/backoffice/external/backend-api'; -import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry'; -import '@umbraco-cms/backoffice/object-type'; - -@customElement('umb-relation-type-workspace-view-relation-type') -export class UmbRelationTypeWorkspaceViewRelationTypeElement extends UmbLitElement implements UmbWorkspaceViewElement { - @state() - private _relationType?: RelationTypeResponseModel; - - #workspaceContext?: typeof UMB_RELATION_TYPE_WORKSPACE_CONTEXT.TYPE; - - constructor() { - super(); - - this.consumeContext(UMB_RELATION_TYPE_WORKSPACE_CONTEXT, (instance) => { - this.#workspaceContext = instance; - this._observeRelationType(); - }); - } - - private _observeRelationType() { - if (!this.#workspaceContext) { - return; - } - - this.observe(this.#workspaceContext.data, (relationType) => { - if (!relationType) return; - - this._relationType = relationType; - }); - } - - #handleDirectionChange(event: UUIRadioGroupEvent) { - const target = event.target as UUIRadioGroupElement; - const value = target.value === 'true'; - this.#workspaceContext?.update('isBidirectional', value); - } - - #handleIsDependencyChange(event: UUIBooleanInputEvent) { - const target = event.target as UUIToggleElement; - const value = target.checked; - this.#workspaceContext?.update('isDependency', value); - } - - render() { - return html` - - - - - - - - ${this.#renderParentProperty()} - ${this.#renderChildProperty()} - - - - - `; - } - - #onParentObjectTypeChange(event: UUISelectEvent) { - const value = event.target.value as string; - this.#workspaceContext?.update('parentObjectType', value); - } - #onChildObjectTypeChange(event: UUISelectEvent) { - const value = event.target.value as string; - this.#workspaceContext?.update('childObjectType', value); - } - - #renderParentProperty() { - if (!this.#workspaceContext?.getIsNew() && this._relationType) - return html`
${this._relationType.parentObjectTypeName}
`; - - return html` - - `; - } - - #renderChildProperty() { - if (!this.#workspaceContext?.getIsNew() && this._relationType) - return html`
${this._relationType.childObjectTypeName}
`; - - return html` - - `; - } - - static styles = [ - css` - :host { - display: block; - margin: var(--uui-size-layout-1); - } - `, - ]; -} - -export default UmbRelationTypeWorkspaceViewRelationTypeElement; - -declare global { - interface HTMLElementTagNameMap { - 'umb-relation-type-workspace-view-relation-type': UmbRelationTypeWorkspaceViewRelationTypeElement; - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/views/relation-type/relation-type-workspace-view-relation-type.stories.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/views/relation-type/relation-type-workspace-view-relation-type.stories.ts deleted file mode 100644 index 21106ae32e..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/views/relation-type/relation-type-workspace-view-relation-type.stories.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { Meta, Story } from '@storybook/web-components'; -import type { UmbRelationTypeWorkspaceViewRelationTypeElement } from './relation-type-workspace-view-relation-type.element.js'; -import { html } from '@umbraco-cms/backoffice/external/lit'; - -//import { data } from '../../../../../core/mocks/data/relation-type.data.js'; - -import './relation-type-workspace-view-relation-type.element.js'; -//import { UmbRelationTypeWorkspaceContext } from '../../workspace-relation-type.context.js'; - -export default { - title: 'Workspaces/Relation Type/Views/RelationType', - component: 'umb-relation-type-workspace-view-relation-type', - id: 'umb-relation-type-workspace-view-relation-type', - decorators: [ - (story) => { - return html`TODO: make use of mocked workspace context??`; - /*html` - ${story()} - `,*/ - }, - ], -} as Meta; - -export const AAAOverview: Story = () => - html` `; -AAAOverview.storyName = 'Overview'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/views/relation/workspace-view-relation-type-relation.element.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/views/relation/workspace-view-relation-type-relation.element.ts deleted file mode 100644 index 8a757de430..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/views/relation/workspace-view-relation-type-relation.element.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { UMB_RELATION_TYPE_WORKSPACE_CONTEXT } from '../../relation-type-workspace.context-token.js'; -import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; -import type { UmbTableColumn, UmbTableConfig, UmbTableItem } from '@umbraco-cms/backoffice/components'; -import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import type { RelationResponseModel } from '@umbraco-cms/backoffice/external/backend-api'; -import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry'; - -@customElement('umb-workspace-view-relation-type-relation') -export class UmbWorkspaceViewRelationTypeRelationElement extends UmbLitElement implements UmbWorkspaceViewElement { - //TODO Use real data - @state() - _relations: Array = []; - - #workspaceContext?: typeof UMB_RELATION_TYPE_WORKSPACE_CONTEXT.TYPE; - - constructor() { - super(); - - this.consumeContext(UMB_RELATION_TYPE_WORKSPACE_CONTEXT, (instance) => { - this.#workspaceContext = instance; - this.#getRelations(); - }); - } - - async #getRelations() { - if (!this.#workspaceContext) { - return; - } - - const response = await this.#workspaceContext.getRelations(); - this._relations = response.data?.items ?? []; - } - - private _tableConfig: UmbTableConfig = { - allowSelection: false, - hideIcon: true, - }; - - private _tableColumns: Array = [ - { - name: 'Parent', - alias: 'parent', - }, - { - name: 'Child', - alias: 'child', - }, - { - name: 'Created', - alias: 'created', - }, - { - name: 'Comment', - alias: 'comment', - }, - ]; - - private get _tableItems(): UmbTableItem[] { - return this._relations.map((relation) => { - return { - id: relation.parentId + '-' + relation.childId, // Add the missing id property - data: [ - { - columnAlias: 'parent', - value: relation.parentName, - }, - { - columnAlias: 'child', - value: relation.childName, - }, - { - columnAlias: 'created', - value: relation.createDate, - }, - { - columnAlias: 'comment', - value: relation.comment, - }, - ], - }; - }); - } - - render() { - return html` - - `; - } - - static styles = [ - UmbTextStyles, - css` - :host { - display: block; - margin: var(--uui-size-layout-1); - } - `, - ]; -} - -export default UmbWorkspaceViewRelationTypeRelationElement; - -declare global { - interface HTMLElementTagNameMap { - 'umb-workspace-view-relation-type-relation': UmbWorkspaceViewRelationTypeRelationElement; - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/views/relation/workspace-view-relation-type-relation.stories.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/views/relation/workspace-view-relation-type-relation.stories.ts deleted file mode 100644 index cae6902234..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relation-types/workspace/views/relation/workspace-view-relation-type-relation.stories.ts +++ /dev/null @@ -1,26 +0,0 @@ -import './workspace-view-relation-type-relation.element.js'; - -import type { Meta, Story } from '@storybook/web-components'; -import type { UmbWorkspaceViewRelationTypeRelationElement } from './workspace-view-relation-type-relation.element.js'; -import { html } from '@umbraco-cms/backoffice/external/lit'; - -//import { data } from '../../../../../core/mocks/data/relation-type.data.js'; -//import { UmbRelationTypeContext } from '../../relation-type.context.js'; - -export default { - title: 'Workspaces/Relation Type/Views/Relation', - component: 'umb-workspace-view-relation-type-relation', - id: 'umb-workspace-view-relation-type-relation', - decorators: [ - (story) => { - return html`TODO: make use of mocked workspace context??`; - /*html` - ${story()} - `,*/ - }, - ], -} as Meta; - -export const AAAOverview: Story = () => - html` `; -AAAOverview.storyName = 'Overview'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/index.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/index.ts new file mode 100644 index 0000000000..58c9a9b250 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/index.ts @@ -0,0 +1 @@ +export { UmbRelationCollectionRepository } from './repository/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/manifests.ts new file mode 100644 index 0000000000..c48b1c6d57 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/manifests.ts @@ -0,0 +1,3 @@ +import { manifests as collectionRepositoryManifests } from './repository/manifests.js'; + +export const manifests = [...collectionRepositoryManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/repository/index.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/repository/index.ts new file mode 100644 index 0000000000..5eb84c21ac --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/repository/index.ts @@ -0,0 +1,2 @@ +export { UMB_RELATION_COLLECTION_REPOSITORY_ALIAS } from './manifests.js'; +export { UmbRelationCollectionRepository } from './relation-collection.repository.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/repository/manifests.ts new file mode 100644 index 0000000000..48f85915fb --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/repository/manifests.ts @@ -0,0 +1,12 @@ +import type { ManifestRepository } from '@umbraco-cms/backoffice/extension-registry'; + +export const UMB_RELATION_COLLECTION_REPOSITORY_ALIAS = 'Umb.Repository.Relation.Collection'; + +const repository: ManifestRepository = { + type: 'repository', + alias: UMB_RELATION_COLLECTION_REPOSITORY_ALIAS, + name: 'Relation Collection Repository', + api: () => import('./relation-collection.repository.js'), +}; + +export const manifests = [repository]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/repository/relation-collection.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/repository/relation-collection.repository.ts new file mode 100644 index 0000000000..c07fd79cd1 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/repository/relation-collection.repository.ts @@ -0,0 +1,21 @@ +import type { UmbRelationCollectionFilterModel } from '../types.js'; +import { UmbRelationCollectionServerDataSource } from './relation-collection.server.data-source.js'; +import type { UmbRelationCollectionDataSource } from './types.js'; +import type { UmbCollectionRepository } from '@umbraco-cms/backoffice/collection'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; + +export class UmbRelationCollectionRepository implements UmbCollectionRepository { + #collectionSource: UmbRelationCollectionDataSource; + + constructor(host: UmbControllerHost) { + this.#collectionSource = new UmbRelationCollectionServerDataSource(host); + } + + async requestCollection(filter: UmbRelationCollectionFilterModel) { + return this.#collectionSource.getCollection(filter); + } + + destroy(): void {} +} + +export default UmbRelationCollectionRepository; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/repository/relation-collection.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/repository/relation-collection.server.data-source.ts new file mode 100644 index 0000000000..48d9103712 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/repository/relation-collection.server.data-source.ts @@ -0,0 +1,70 @@ +import type { UmbRelationCollectionFilterModel } from '../types.js'; +import type { UmbRelationDetailModel } from '../../types.js'; +import { UMB_RELATION_ENTITY_TYPE } from '../../entity.js'; +import type { UmbCollectionDataSource } from '@umbraco-cms/backoffice/collection'; +import { RelationResource } from '@umbraco-cms/backoffice/external/backend-api'; +import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; + +/** + * A data source that fetches the relation collection data from the server. + * @export + * @class UmbRelationCollectionServerDataSource + * @implements {UmbCollectionDataSource} + */ +export class UmbRelationCollectionServerDataSource implements UmbCollectionDataSource { + #host: UmbControllerHost; + + /** + * Creates an instance of UmbRelationCollectionServerDataSource. + * @param {UmbControllerHost} host + * @memberof UmbRelationCollectionServerDataSource + */ + constructor(host: UmbControllerHost) { + this.#host = host; + } + + /** + * Gets the relation collection filtered by the given filter. + * @param {UmbRelationCollectionFilterModel} filter + * @return {*} + * @memberof UmbRelationCollectionServerDataSource + */ + async getCollection(filter: UmbRelationCollectionFilterModel) { + const requestBody = { + skip: filter.skip, + take: filter.take, + id: filter.relationType.unique, + }; + + const { data, error } = await tryExecuteAndNotify(this.#host, RelationResource.getRelationTypeById(requestBody)); + + if (data) { + const items = data.items.map((item) => { + const model: UmbRelationDetailModel = { + unique: item.id, + entityType: UMB_RELATION_ENTITY_TYPE, + relationType: { + unique: item.relationType.id, + }, + parent: { + unique: item.parent.id, + name: item.parent.name || '', + }, + child: { + unique: item.child.id, + name: item.child.name || '', + }, + createDate: item.createDate, + comment: item.comment || '', + }; + + return model; + }); + + return { data: { items, total: data.total } }; + } + + return { error }; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/repository/types.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/repository/types.ts new file mode 100644 index 0000000000..cfc5f85b3c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/repository/types.ts @@ -0,0 +1,8 @@ +import type { UmbRelationDetailModel } from '../../types.js'; +import type { UmbRelationCollectionFilterModel } from '../types.js'; +import type { UmbCollectionDataSource } from '@umbraco-cms/backoffice/collection'; + +export type UmbRelationCollectionDataSource = UmbCollectionDataSource< + UmbRelationDetailModel, + UmbRelationCollectionFilterModel +>; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/types.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/types.ts new file mode 100644 index 0000000000..b2cb1f1151 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/collection/types.ts @@ -0,0 +1,7 @@ +export interface UmbRelationCollectionFilterModel { + relationType: { + unique: string; + }; + skip?: number; + take?: number; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entities.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entities.ts deleted file mode 100644 index 197d94a6e7..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entities.ts +++ /dev/null @@ -1 +0,0 @@ -export const UMB_RELATION_ENTITY_TYPE = 'relation'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity.ts new file mode 100644 index 0000000000..02bf0e3a1f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/entity.ts @@ -0,0 +1,3 @@ +export const UMB_RELATION_ENTITY_TYPE = 'relation'; + +export type UmbRelationEntityType = typeof UMB_RELATION_ENTITY_TYPE; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/index.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/index.ts index 7bbcc83722..5b1cfeac2a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/index.ts @@ -1,2 +1,5 @@ -export * from './repository/index.js'; -export * from './entities.js'; +export * from './collection/index.js'; +export * from './entity.js'; +export * from './utils.js'; + +export type * from './types.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/manifests.ts index 4e1826b900..a41c459c34 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/manifests.ts @@ -1,3 +1,3 @@ -import { manifests as repositoryManifests } from './repository/manifests.js'; +import { manifests as collectionManifests } from './collection/manifests.js'; -export const manifests = [...repositoryManifests]; +export const manifests = [...collectionManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/repository/index.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/repository/index.ts deleted file mode 100644 index 5a2d860e87..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/repository/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './relation.repository.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/repository/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/repository/manifests.ts deleted file mode 100644 index f8cd40d0ab..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/repository/manifests.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { ManifestRepository } from '@umbraco-cms/backoffice/extension-registry'; - -export const UMB_RELATION_REPOSITORY_ALIAS = 'Umb.Repository.Relation'; - -const repository: ManifestRepository = { - type: 'repository', - alias: UMB_RELATION_REPOSITORY_ALIAS, - name: 'Relation Repository', - api: () => import('./relation.repository.js'), -}; - -export const manifests = [repository]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/repository/relation.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/repository/relation.repository.ts deleted file mode 100644 index 86565f5ca1..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/repository/relation.repository.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { UmbRelationServerDataSource } from './sources/relation.server.data.js'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; -import type { UmbNotificationContext } from '@umbraco-cms/backoffice/notification'; -import { UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification'; -import type { UmbApi } from '@umbraco-cms/backoffice/extension-api'; - -export class UmbRelationRepository extends UmbControllerBase implements UmbApi { - #init!: Promise; - - #detailDataSource: UmbRelationServerDataSource; - #notificationContext?: UmbNotificationContext; - - constructor(host: UmbControllerHost) { - super(host); - - // TODO: figure out how spin up get the correct data source - this.#detailDataSource = new UmbRelationServerDataSource(this._host); - - this.#init = Promise.all([ - this.consumeContext(UMB_NOTIFICATION_CONTEXT, (instance) => { - this.#notificationContext = instance; - }).asPromise(), - ]); - } - - async requestById(id: string) { - await this.#init; - - // TODO: should we show a notification if the id is missing? - // Investigate what is best for Acceptance testing, cause in that perspective a thrown error might be the best choice? - if (!id) { - throw new Error('Id is missing'); - } - - const { data, error } = await this.#detailDataSource.read(id); - - return { data, error }; - } - - async requestChildRelationById(childId: string, relationTypeAlias?: string) { - await this.#init; - - // TODO: should we show a notification if the id is missing? - // Investigate what is best for Acceptance testing, cause in that perspective a thrown error might be the best choice? - if (!childId) { - throw new Error('Id is missing'); - } - - const { data, error } = await this.#detailDataSource.readChildRelations(childId, relationTypeAlias); - - return { data, error }; - } -} - -export default UmbRelationRepository; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/repository/sources/relation.server.data.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/repository/sources/relation.server.data.ts deleted file mode 100644 index 91fa150b7d..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/repository/sources/relation.server.data.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { RelationResource } from '@umbraco-cms/backoffice/external/backend-api'; -import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; -import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; - -/** - * A data source for the Relation that fetches data from the server - * @export - * @class UmbRelationServerDataSource - * @implements {RepositoryDetailDataSource} - */ -export class UmbRelationServerDataSource { - #host: UmbControllerHost; - - /** - * Creates an instance of UmbRelationServerDataSource. - * @param {UmbControllerHost} host - * @memberof UmbRelationServerDataSource - */ - constructor(host: UmbControllerHost) { - this.#host = host; - } - - /** - * Fetches relations by the given id from the server - * @param {string} id - * @return {*} - * @memberof UmbRelationServerDataSource - */ - async read(id: string) { - if (!id) { - throw new Error('Id is missing'); - } - - return tryExecuteAndNotify( - this.#host, - RelationResource.getRelationTypeById({ - id, - }), - ); - } - - /** - * Fetches relations by the given id from the server - * @param {string} childId - * @return {*} - * @memberof UmbRelationServerDataSource - */ - async readChildRelations(childId: string, relationTypeAlias?: string) { - if (!childId) { - throw new Error('Id is missing'); - } - - return tryExecuteAndNotify( - this.#host, - RelationResource.getRelationChildRelationByChildId({ - childId, - relationTypeAlias, - }), - ); - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/types.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/types.ts new file mode 100644 index 0000000000..08536e1a3f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/types.ts @@ -0,0 +1,29 @@ +import type { UmbRelationEntityType } from './entity.js'; +import type { + DefaultReferenceResponseModel, + DocumentReferenceResponseModel, + MediaReferenceResponseModel, +} from '@umbraco-cms/backoffice/external/backend-api'; + +export interface UmbRelationDetailModel { + unique: string; + entityType: UmbRelationEntityType; + relationType: { + unique: string; + }; + parent: { + unique: string; + name: string; + }; + child: { + unique: string; + name: string; + }; + createDate: string; + comment: string | null; +} + +export type UmbReferenceModel = + | DefaultReferenceResponseModel + | DocumentReferenceResponseModel + | MediaReferenceResponseModel; diff --git a/src/Umbraco.Web.UI.Client/src/packages/relations/relations/utils.ts b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/utils.ts new file mode 100644 index 0000000000..b27936d26a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/relations/relations/utils.ts @@ -0,0 +1,18 @@ +import type { UmbReferenceModel } from './types.js'; +import type { + DefaultReferenceResponseModel, + DocumentReferenceResponseModel, + MediaReferenceResponseModel, +} from '@umbraco-cms/backoffice/external/backend-api'; + +export function isDocumentReference(item: UmbReferenceModel): item is DocumentReferenceResponseModel { + return typeof (item as DocumentReferenceResponseModel).documentType !== 'undefined'; +} + +export function isMediaReference(item: UmbReferenceModel): item is MediaReferenceResponseModel { + return typeof (item as MediaReferenceResponseModel).mediaType !== 'undefined'; +} + +export function isDefaultReference(item: UmbReferenceModel): item is DefaultReferenceResponseModel { + return typeof (item as DefaultReferenceResponseModel).type !== 'undefined'; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/profile/current-user-profile-user-profile-app.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/profile/current-user-profile-user-profile-app.element.ts index 95253ff159..0916731b84 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/current-user/profile/current-user-profile-user-profile-app.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/current-user/profile/current-user-profile-user-profile-app.element.ts @@ -34,7 +34,7 @@ export class UmbCurrentUserProfileUserProfileAppElement extends UmbLitElement { private _edit() { if (!this._currentUser) return; - history.pushState(null, '', 'section/user-management/view/users/user/' + this._currentUser.unique); //TODO Change to a tag with href and make dynamic + history.pushState(null, '', 'section/user-management/view/users/user/edit/' + this._currentUser.unique); //TODO Change to a tag with href and make dynamic //TODO Implement modal routing for the current-user-modal, so that the modal closes when navigating to the edit profile page } async #changePassword() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/views/user-group-table-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/views/user-group-table-collection-view.element.ts index ff5eb2497b..06e927feb2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/views/user-group-table-collection-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/collection/views/user-group-table-collection-view.element.ts @@ -1,5 +1,5 @@ import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; +import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collection'; import { UMB_DEFAULT_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/collection'; @@ -129,14 +129,7 @@ export class UmbUserGroupCollectionTableViewElement extends UmbLitElement { `; } - static styles = [ - UmbTextStyles, - css` - umb-table { - padding: 0; - } - `, - ]; + static styles = [UmbTextStyles]; } export default UmbUserGroupCollectionTableViewElement; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/entity.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/entity.ts index 2ff237dc91..40fc592fed 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/entity.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/entity.ts @@ -1,3 +1,3 @@ -export const UMB_USER_GROUP_ENTITY_TYPE = 'user'; +export const UMB_USER_GROUP_ENTITY_TYPE = 'user-group'; export type UmbUserGroupEntityType = typeof UMB_USER_GROUP_ENTITY_TYPE; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/user-group-section-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/user-group-section-view.element.ts index 460f09cca2..073f886d3f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/user-group-section-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user-group/section-view/user-group-section-view.element.ts @@ -1,9 +1,11 @@ import { UMB_USER_GROUP_COLLECTION_ALIAS } from '../collection/index.js'; +import { UMB_USER_GROUP_ENTITY_TYPE } from '../entity.js'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import type { UmbRoute } from '@umbraco-cms/backoffice/router'; -import { UMB_USER_GROUP_ENTITY_TYPE } from '../entity.js'; +import { UmbCollectionElement } from '@umbraco-cms/backoffice/collection'; +import { UmbWorkspaceElement } from '@umbraco-cms/backoffice/workspace'; @customElement('umb-user-group-section-view') export class UmbUserGroupSectionViewElement extends UmbLitElement { @@ -11,7 +13,7 @@ export class UmbUserGroupSectionViewElement extends UmbLitElement { { path: 'collection', component: () => { - const element = document.createElement('umb-collection'); + const element = new UmbCollectionElement(); element.setAttribute('alias', UMB_USER_GROUP_COLLECTION_ALIAS); return element; }, @@ -19,8 +21,8 @@ export class UmbUserGroupSectionViewElement extends UmbLitElement { { path: 'user-group', component: () => { - const element = document.createElement('umb-workspace'); - element.setAttribute('entityType', UMB_USER_GROUP_ENTITY_TYPE); + const element = new UmbWorkspaceElement(); + element.setAttribute('entity-type', UMB_USER_GROUP_ENTITY_TYPE); return element; }, }, diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/grid/user-grid-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/grid/user-grid-collection-view.element.ts index f0d3bdccdf..9dc4c11ec5 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/grid/user-grid-collection-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/grid/user-grid-collection-view.element.ts @@ -51,9 +51,9 @@ export class UmbUserGridCollectionViewElement extends UmbLitElement { } //TODO How should we handle url stuff? - private _handleOpenCard(id: string) { + private _handleOpenCard(unique: string) { //TODO this will not be needed when cards works as links with href - history.pushState(null, '', 'section/user-management/view/users/user/' + id); //TODO Change to a tag with href and make dynamic + history.pushState(null, '', 'section/user-management/view/users/user/edit/' + unique); //TODO Change to a tag with href and make dynamic } #onSelect(user: UmbUserDetailModel) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/manifests.ts index bcdccca167..f65daedc51 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/manifests.ts @@ -7,7 +7,7 @@ const tableCollectionView: ManifestCollectionView = { type: 'collectionView', alias: UMB_COLLECTION_VIEW_USER_TABLE, name: 'User Table Collection View', - js: () => import('./table/user-table-collection-view.element.js'), + element: () => import('./table/user-table-collection-view.element.js'), meta: { label: 'Table', icon: 'icon-list', @@ -26,8 +26,8 @@ export const UMB_COLLECTION_VIEW_USER_GRID = 'Umb.CollectionView.User.Grid'; const gridCollectionView: ManifestCollectionView = { type: 'collectionView', alias: UMB_COLLECTION_VIEW_USER_GRID, - name: 'User Table Collection View', - js: () => import('./grid/user-grid-collection-view.element.js'), + name: 'User Grid Collection View', + element: () => import('./grid/user-grid-collection-view.element.js'), weight: 200, meta: { label: 'Grid', diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/table/column-layouts/name/user-table-name-column-layout.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/table/column-layouts/name/user-table-name-column-layout.element.ts index 620eee98c7..0fd787f4e4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/table/column-layouts/name/user-table-name-column-layout.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/table/column-layouts/name/user-table-name-column-layout.element.ts @@ -40,7 +40,7 @@ export class UmbUserTableNameColumnLayoutElement extends LitElement { .name=${this.value.name || 'Unknown'} img-src=${ifDefined(this.value.avatarUrls.length > 0 ? avatarUrls[0].url : undefined)} img-srcset=${ifDefined(this.value.avatarUrls.length > 0 ? avatarSrcset : undefined)}> - ${this.value.name}
`; diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/table/user-table-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/table/user-table-collection-view.element.ts index 144849bd97..1a9e9959aa 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/table/user-table-collection-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/collection/views/table/user-table-collection-view.element.ts @@ -181,11 +181,6 @@ export class UmbUserTableCollectionViewElement extends UmbLitElement { display: flex; flex-direction: column; } - - umb-table { - padding: 0; - margin: 0 var(--uui-size-layout-1) var(--uui-size-layout-1); - } `, ]; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/modals/create/create-user-success-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/modals/create/create-user-success-modal.element.ts index e39b25cd6e..30d7c46716 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/modals/create/create-user-success-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/modals/create/create-user-success-modal.element.ts @@ -72,7 +72,7 @@ export class UmbCreateUserSuccessModalElement extends UmbModalBaseElement< #onGoToProfile = (event: Event) => { event.stopPropagation(); this._submitModal(); - history.pushState(null, '', 'section/user-management/view/users/user/' + this.data?.user.unique); //TODO: URL Should be dynamic + history.pushState(null, '', 'section/user-management/view/users/user/edit/' + this.data?.user.unique); //TODO: URL Should be dynamic }; render() { diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/users-section-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/users-section-view.element.ts index abeb461c34..52eb5e4152 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/users-section-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/section-view/users-section-view.element.ts @@ -4,6 +4,8 @@ import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import type { UmbRoute } from '@umbraco-cms/backoffice/router'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; +import { UmbCollectionElement } from '@umbraco-cms/backoffice/collection'; +import { UmbWorkspaceElement } from '@umbraco-cms/backoffice/workspace'; @customElement('umb-section-view-users') export class UmbSectionViewUsersElement extends UmbLitElement { @@ -11,7 +13,7 @@ export class UmbSectionViewUsersElement extends UmbLitElement { { path: 'collection', component: () => { - const element = document.createElement('umb-collection'); + const element = new UmbCollectionElement(); element.setAttribute('alias', UMB_USER_COLLECTION_ALIAS); return element; }, @@ -19,8 +21,8 @@ export class UmbSectionViewUsersElement extends UmbLitElement { { path: 'user', component: () => { - const element = document.createElement('umb-workspace'); - element.setAttribute('entityType', UMB_USER_ENTITY_TYPE); + const element = new UmbWorkspaceElement(); + element.setAttribute('entity-type', UMB_USER_ENTITY_TYPE); return element; }, }, diff --git a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context.ts index c83f21c2f2..972e2870da 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/user/user/workspace/user-workspace.context.ts @@ -28,9 +28,10 @@ export class UmbUserWorkspaceContext constructor(host: UmbControllerHost) { super(host, UMB_USER_WORKSPACE_ALIAS); + this.routes.setRoutes([ { - path: ':id', + path: 'edit/:id', component: UmbUserWorkspaceEditorElement, setup: (component, info) => { const id = info.match.params.id;