diff --git a/src/Umbraco.Web.UI.Client/.vscode/settings.json b/src/Umbraco.Web.UI.Client/.vscode/settings.json index 04238ad7e0..26b5d4b347 100644 --- a/src/Umbraco.Web.UI.Client/.vscode/settings.json +++ b/src/Umbraco.Web.UI.Client/.vscode/settings.json @@ -5,8 +5,10 @@ "Backoffice", "combobox", "Elementable", + "Niels", "pickable", "templating", + "umbraco", "variantable" ], "exportall.config.folderListener": [], 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 30a7c34aea..2e8f501cbc 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 @@ -26,9 +26,13 @@ export type { CopyDataTypeRequestModel } from './models/CopyDataTypeRequestModel export type { CopyDocumentRequestModel } from './models/CopyDocumentRequestModel'; export type { CreateContentRequestModelBaseDocumentValueModelDocumentVariantRequestModel } from './models/CreateContentRequestModelBaseDocumentValueModelDocumentVariantRequestModel'; export type { CreateContentRequestModelBaseMediaValueModelMediaVariantRequestModel } from './models/CreateContentRequestModelBaseMediaValueModelMediaVariantRequestModel'; +export type { CreateContentTypeRequestModelBaseCreateDocumentTypePropertyTypeRequestModelCreateDocumentTypePropertyTypeContainerRequestModel } from './models/CreateContentTypeRequestModelBaseCreateDocumentTypePropertyTypeRequestModelCreateDocumentTypePropertyTypeContainerRequestModel'; export type { CreateDataTypeRequestModel } from './models/CreateDataTypeRequestModel'; export type { CreateDictionaryItemRequestModel } from './models/CreateDictionaryItemRequestModel'; export type { CreateDocumentRequestModel } from './models/CreateDocumentRequestModel'; +export type { CreateDocumentTypePropertyTypeContainerRequestModel } from './models/CreateDocumentTypePropertyTypeContainerRequestModel'; +export type { CreateDocumentTypePropertyTypeRequestModel } from './models/CreateDocumentTypePropertyTypeRequestModel'; +export type { CreateDocumentTypeRequestModel } from './models/CreateDocumentTypeRequestModel'; export type { CreateFolderRequestModel } from './models/CreateFolderRequestModel'; export type { CreateLanguageRequestModel } from './models/CreateLanguageRequestModel'; export type { CreateMediaRequestModel } from './models/CreateMediaRequestModel'; @@ -44,6 +48,7 @@ export type { CreateUserGroupRequestModel } from './models/CreateUserGroupReques export type { CreateUserRequestModel } from './models/CreateUserRequestModel'; export type { CreateUserResponseModel } from './models/CreateUserResponseModel'; export type { CultureReponseModel } from './models/CultureReponseModel'; +export type { CurrentUserResponseModel } from './models/CurrentUserResponseModel'; export type { DatabaseInstallResponseModel } from './models/DatabaseInstallResponseModel'; export type { DatabaseSettingsPresentationModel } from './models/DatabaseSettingsPresentationModel'; export type { DataTypeItemResponseModel } from './models/DataTypeItemResponseModel'; @@ -108,6 +113,8 @@ export type { ItemResponseModelBaseModel } from './models/ItemResponseModelBaseM export type { LanguageItemResponseModel } from './models/LanguageItemResponseModel'; export type { LanguageModelBaseModel } from './models/LanguageModelBaseModel'; export type { LanguageResponseModel } from './models/LanguageResponseModel'; +export type { LinkedLoginModel } from './models/LinkedLoginModel'; +export type { LinkedLoginsRequestModel } from './models/LinkedLoginsRequestModel'; export type { LoggerResponseModel } from './models/LoggerResponseModel'; export type { LoginRequestModel } from './models/LoginRequestModel'; export type { LogLevelCountsReponseModel } from './models/LogLevelCountsReponseModel'; @@ -186,8 +193,8 @@ export type { ProblemDetailsModel } from './models/ProblemDetailsModel'; export type { ProfilingStatusRequestModel } from './models/ProfilingStatusRequestModel'; export type { ProfilingStatusResponseModel } from './models/ProfilingStatusResponseModel'; export type { PropertyTypeAppearanceModel } from './models/PropertyTypeAppearanceModel'; -export type { PropertyTypeContainerResponseModelBaseModel } from './models/PropertyTypeContainerResponseModelBaseModel'; -export type { PropertyTypeResponseModelBaseModel } from './models/PropertyTypeResponseModelBaseModel'; +export type { PropertyTypeContainerModelBaseModel } from './models/PropertyTypeContainerModelBaseModel'; +export type { PropertyTypeModelBaseModel } from './models/PropertyTypeModelBaseModel'; export type { PropertyTypeValidationModel } from './models/PropertyTypeValidationModel'; export { PublishedStateModel } from './models/PublishedStateModel'; export type { RecycleBinItemResponseModel } from './models/RecycleBinItemResponseModel'; @@ -213,6 +220,7 @@ export type { SearcherResponseModel } from './models/SearcherResponseModel'; export type { SearchResultResponseModel } from './models/SearchResultResponseModel'; export type { ServerStatusResponseModel } from './models/ServerStatusResponseModel'; export type { SetAvatarRequestModel } from './models/SetAvatarRequestModel'; +export type { SetTourStatusRequestModel } from './models/SetTourStatusRequestModel'; export type { SnippetItemResponseModel } from './models/SnippetItemResponseModel'; export type { StaticFileItemResponseModel } from './models/StaticFileItemResponseModel'; export { StatusResultTypeModel } from './models/StatusResultTypeModel'; @@ -242,14 +250,19 @@ export type { TemporaryFileResponseModel } from './models/TemporaryFileResponseM export type { TextFileResponseModelBaseModel } from './models/TextFileResponseModelBaseModel'; export type { TextFileUpdateModel } from './models/TextFileUpdateModel'; export type { TextFileViewModelBaseModel } from './models/TextFileViewModelBaseModel'; +export type { TourStatusModel } from './models/TourStatusModel'; export type { TreeItemPresentationModel } from './models/TreeItemPresentationModel'; export type { UnlockUsersRequestModel } from './models/UnlockUsersRequestModel'; export type { UpdateContentRequestModelBaseDocumentValueModelDocumentVariantRequestModel } from './models/UpdateContentRequestModelBaseDocumentValueModelDocumentVariantRequestModel'; export type { UpdateContentRequestModelBaseMediaValueModelMediaVariantRequestModel } from './models/UpdateContentRequestModelBaseMediaValueModelMediaVariantRequestModel'; +export type { UpdateContentTypeRequestModelBaseUpdateDocumentTypePropertyTypeRequestModelUpdateDocumentTypePropertyTypeContainerRequestModel } from './models/UpdateContentTypeRequestModelBaseUpdateDocumentTypePropertyTypeRequestModelUpdateDocumentTypePropertyTypeContainerRequestModel'; export type { UpdateDataTypeRequestModel } from './models/UpdateDataTypeRequestModel'; export type { UpdateDictionaryItemRequestModel } from './models/UpdateDictionaryItemRequestModel'; export type { UpdateDocumentNotificationsRequestModel } from './models/UpdateDocumentNotificationsRequestModel'; export type { UpdateDocumentRequestModel } from './models/UpdateDocumentRequestModel'; +export type { UpdateDocumentTypePropertyTypeContainerRequestModel } from './models/UpdateDocumentTypePropertyTypeContainerRequestModel'; +export type { UpdateDocumentTypePropertyTypeRequestModel } from './models/UpdateDocumentTypePropertyTypeRequestModel'; +export type { UpdateDocumentTypeRequestModel } from './models/UpdateDocumentTypeRequestModel'; export type { UpdateDomainsRequestModel } from './models/UpdateDomainsRequestModel'; export type { UpdateFolderReponseModel } from './models/UpdateFolderReponseModel'; export type { UpdateLanguageRequestModel } from './models/UpdateLanguageRequestModel'; @@ -265,16 +278,21 @@ export type { UpdateUserGroupRequestModel } from './models/UpdateUserGroupReques export type { UpdateUserGroupsOnUserRequestModel } from './models/UpdateUserGroupsOnUserRequestModel'; export type { UpdateUserRequestModel } from './models/UpdateUserRequestModel'; export type { UpgradeSettingsResponseModel } from './models/UpgradeSettingsResponseModel'; +export type { UserDataModel } from './models/UserDataModel'; +export type { UserDataResponseModel } from './models/UserDataResponseModel'; export type { UserGroupBaseModel } from './models/UserGroupBaseModel'; export type { UserGroupItemResponseModel } from './models/UserGroupItemResponseModel'; export type { UserGroupResponseModel } from './models/UserGroupResponseModel'; export type { UserInstallResponseModel } from './models/UserInstallResponseModel'; export type { UserItemResponseModel } from './models/UserItemResponseModel'; export { UserOrderModel } from './models/UserOrderModel'; +export type { UserPermissionModel } from './models/UserPermissionModel'; +export type { UserPermissionsResponseModel } from './models/UserPermissionsResponseModel'; export type { UserPresentationBaseModel } from './models/UserPresentationBaseModel'; export type { UserResponseModel } from './models/UserResponseModel'; export type { UserSettingsModel } from './models/UserSettingsModel'; export { UserStateModel } from './models/UserStateModel'; +export type { UserTourStatusesResponseModel } from './models/UserTourStatusesResponseModel'; export type { ValueModelBaseModel } from './models/ValueModelBaseModel'; export type { VariantModelBaseModel } from './models/VariantModelBaseModel'; export type { VariantResponseModelBaseModel } from './models/VariantResponseModelBaseModel'; @@ -319,6 +337,7 @@ export { TagResource } from './services/TagResource'; 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'; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentTypeResponseModelBaseDocumentTypePropertyTypeResponseModelDocumentTypePropertyTypeContainerResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentTypeResponseModelBaseDocumentTypePropertyTypeResponseModelDocumentTypePropertyTypeContainerResponseModel.ts index 8427bc56c6..9c0db74804 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentTypeResponseModelBaseDocumentTypePropertyTypeResponseModelDocumentTypePropertyTypeContainerResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentTypeResponseModelBaseDocumentTypePropertyTypeResponseModelDocumentTypePropertyTypeContainerResponseModel.ts @@ -8,7 +8,6 @@ import type { DocumentTypePropertyTypeContainerResponseModel } from './DocumentT import type { DocumentTypePropertyTypeResponseModel } from './DocumentTypePropertyTypeResponseModel'; export type ContentTypeResponseModelBaseDocumentTypePropertyTypeResponseModelDocumentTypePropertyTypeContainerResponseModel = { - id?: string; alias?: string; name?: string; description?: string | null; @@ -21,5 +20,6 @@ export type ContentTypeResponseModelBaseDocumentTypePropertyTypeResponseModelDoc containers?: Array; allowedContentTypes?: Array; compositions?: Array; + id?: string; }; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentTypeResponseModelBaseMediaTypePropertyTypeResponseModelMediaTypePropertyTypeContainerResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentTypeResponseModelBaseMediaTypePropertyTypeResponseModelMediaTypePropertyTypeContainerResponseModel.ts index c8285cef7b..97c4eb3d4f 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentTypeResponseModelBaseMediaTypePropertyTypeResponseModelMediaTypePropertyTypeContainerResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/ContentTypeResponseModelBaseMediaTypePropertyTypeResponseModelMediaTypePropertyTypeContainerResponseModel.ts @@ -8,7 +8,6 @@ import type { MediaTypePropertyTypeContainerResponseModel } from './MediaTypePro import type { MediaTypePropertyTypeResponseModel } from './MediaTypePropertyTypeResponseModel'; export type ContentTypeResponseModelBaseMediaTypePropertyTypeResponseModelMediaTypePropertyTypeContainerResponseModel = { - id?: string; alias?: string; name?: string; description?: string | null; @@ -21,5 +20,6 @@ export type ContentTypeResponseModelBaseMediaTypePropertyTypeResponseModelMediaT containers?: Array; allowedContentTypes?: Array; compositions?: Array; + id?: string; }; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateContentTypeRequestModelBaseCreateDocumentTypePropertyTypeRequestModelCreateDocumentTypePropertyTypeContainerRequestModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateContentTypeRequestModelBaseCreateDocumentTypePropertyTypeRequestModelCreateDocumentTypePropertyTypeContainerRequestModel.ts new file mode 100644 index 0000000000..e5500611da --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateContentTypeRequestModelBaseCreateDocumentTypePropertyTypeRequestModelCreateDocumentTypePropertyTypeContainerRequestModel.ts @@ -0,0 +1,24 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { ContentTypeCompositionModel } from './ContentTypeCompositionModel'; +import type { ContentTypeSortModel } from './ContentTypeSortModel'; +import type { CreateDocumentTypePropertyTypeContainerRequestModel } from './CreateDocumentTypePropertyTypeContainerRequestModel'; +import type { CreateDocumentTypePropertyTypeRequestModel } from './CreateDocumentTypePropertyTypeRequestModel'; + +export type CreateContentTypeRequestModelBaseCreateDocumentTypePropertyTypeRequestModelCreateDocumentTypePropertyTypeContainerRequestModel = { + alias?: string; + name?: string; + description?: string | null; + icon?: string; + allowedAsRoot?: boolean; + variesByCulture?: boolean; + variesBySegment?: boolean; + isElement?: boolean; + properties?: Array; + containers?: Array; + allowedContentTypes?: Array; + compositions?: Array; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateDocumentTypePropertyTypeContainerRequestModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateDocumentTypePropertyTypeContainerRequestModel.ts new file mode 100644 index 0000000000..79e628b10c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateDocumentTypePropertyTypeContainerRequestModel.ts @@ -0,0 +1,8 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { PropertyTypeContainerModelBaseModel } from './PropertyTypeContainerModelBaseModel'; + +export type CreateDocumentTypePropertyTypeContainerRequestModel = PropertyTypeContainerModelBaseModel; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateDocumentTypePropertyTypeRequestModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateDocumentTypePropertyTypeRequestModel.ts new file mode 100644 index 0000000000..7728b4df34 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateDocumentTypePropertyTypeRequestModel.ts @@ -0,0 +1,8 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { PropertyTypeModelBaseModel } from './PropertyTypeModelBaseModel'; + +export type CreateDocumentTypePropertyTypeRequestModel = PropertyTypeModelBaseModel; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateDocumentTypeRequestModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateDocumentTypeRequestModel.ts new file mode 100644 index 0000000000..72a9320d48 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CreateDocumentTypeRequestModel.ts @@ -0,0 +1,14 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { ContentTypeCleanupModel } from './ContentTypeCleanupModel'; +import type { CreateContentTypeRequestModelBaseCreateDocumentTypePropertyTypeRequestModelCreateDocumentTypePropertyTypeContainerRequestModel } from './CreateContentTypeRequestModelBaseCreateDocumentTypePropertyTypeRequestModelCreateDocumentTypePropertyTypeContainerRequestModel'; + +export type CreateDocumentTypeRequestModel = (CreateContentTypeRequestModelBaseCreateDocumentTypePropertyTypeRequestModelCreateDocumentTypePropertyTypeContainerRequestModel & { + $type: string; + allowedTemplateIds?: Array; + defaultTemplateId?: string | null; + cleanup?: ContentTypeCleanupModel; +}); + 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 new file mode 100644 index 0000000000..f49ea20f2d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/CurrentUserResponseModel.ts @@ -0,0 +1,19 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type CurrentUserResponseModel = { + $type: string; + id?: string; + email?: string; + userName?: string; + name?: string; + languageIsoCode?: string | null; + contentStartNodeIds?: Array; + mediaStartNodeIds?: Array; + avatarUrls?: Array; + languages?: Array; + hasAccessToAllLanguages?: boolean; + permissions?: Array; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentTypePropertyTypeContainerResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentTypePropertyTypeContainerResponseModel.ts index 83aa9e6459..3ac16db1b0 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentTypePropertyTypeContainerResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentTypePropertyTypeContainerResponseModel.ts @@ -2,7 +2,7 @@ /* tslint:disable */ /* eslint-disable */ -import type { PropertyTypeContainerResponseModelBaseModel } from './PropertyTypeContainerResponseModelBaseModel'; +import type { PropertyTypeContainerModelBaseModel } from './PropertyTypeContainerModelBaseModel'; -export type DocumentTypePropertyTypeContainerResponseModel = PropertyTypeContainerResponseModelBaseModel; +export type DocumentTypePropertyTypeContainerResponseModel = PropertyTypeContainerModelBaseModel; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentTypePropertyTypeResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentTypePropertyTypeResponseModel.ts index c74873bb1b..56a799fc56 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentTypePropertyTypeResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/DocumentTypePropertyTypeResponseModel.ts @@ -2,7 +2,7 @@ /* tslint:disable */ /* eslint-disable */ -import type { PropertyTypeResponseModelBaseModel } from './PropertyTypeResponseModelBaseModel'; +import type { PropertyTypeModelBaseModel } from './PropertyTypeModelBaseModel'; -export type DocumentTypePropertyTypeResponseModel = PropertyTypeResponseModelBaseModel; +export type DocumentTypePropertyTypeResponseModel = PropertyTypeModelBaseModel; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/LinkedLoginModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/LinkedLoginModel.ts new file mode 100644 index 0000000000..71b8862c21 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/LinkedLoginModel.ts @@ -0,0 +1,9 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type LinkedLoginModel = { + providerName?: string; + providerKey?: string; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/LinkedLoginsRequestModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/LinkedLoginsRequestModel.ts new file mode 100644 index 0000000000..c08e6b7811 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/LinkedLoginsRequestModel.ts @@ -0,0 +1,10 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { LinkedLoginModel } from './LinkedLoginModel'; + +export type LinkedLoginsRequestModel = { + linkedLogins?: Array; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaTypePropertyTypeContainerResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaTypePropertyTypeContainerResponseModel.ts index f8a0b7ba60..a7cdb81bec 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaTypePropertyTypeContainerResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaTypePropertyTypeContainerResponseModel.ts @@ -2,7 +2,7 @@ /* tslint:disable */ /* eslint-disable */ -import type { PropertyTypeContainerResponseModelBaseModel } from './PropertyTypeContainerResponseModelBaseModel'; +import type { PropertyTypeContainerModelBaseModel } from './PropertyTypeContainerModelBaseModel'; -export type MediaTypePropertyTypeContainerResponseModel = PropertyTypeContainerResponseModelBaseModel; +export type MediaTypePropertyTypeContainerResponseModel = PropertyTypeContainerModelBaseModel; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaTypePropertyTypeResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaTypePropertyTypeResponseModel.ts index a4d992c86a..f9d3a312b3 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaTypePropertyTypeResponseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/MediaTypePropertyTypeResponseModel.ts @@ -2,7 +2,7 @@ /* tslint:disable */ /* eslint-disable */ -import type { PropertyTypeResponseModelBaseModel } from './PropertyTypeResponseModelBaseModel'; +import type { PropertyTypeModelBaseModel } from './PropertyTypeModelBaseModel'; -export type MediaTypePropertyTypeResponseModel = PropertyTypeResponseModelBaseModel; +export type MediaTypePropertyTypeResponseModel = PropertyTypeModelBaseModel; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PropertyTypeContainerResponseModelBaseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PropertyTypeContainerModelBaseModel.ts similarity index 76% rename from src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PropertyTypeContainerResponseModelBaseModel.ts rename to src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PropertyTypeContainerModelBaseModel.ts index e57942bc53..220459b706 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PropertyTypeContainerResponseModelBaseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PropertyTypeContainerModelBaseModel.ts @@ -2,7 +2,7 @@ /* tslint:disable */ /* eslint-disable */ -export type PropertyTypeContainerResponseModelBaseModel = { +export type PropertyTypeContainerModelBaseModel = { id?: string; parentId?: string | null; name?: string | null; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PropertyTypeResponseModelBaseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PropertyTypeModelBaseModel.ts similarity index 91% rename from src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PropertyTypeResponseModelBaseModel.ts rename to src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PropertyTypeModelBaseModel.ts index c8fe5753df..4d7bc5eda9 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PropertyTypeResponseModelBaseModel.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/PropertyTypeModelBaseModel.ts @@ -5,7 +5,7 @@ import type { PropertyTypeAppearanceModel } from './PropertyTypeAppearanceModel'; import type { PropertyTypeValidationModel } from './PropertyTypeValidationModel'; -export type PropertyTypeResponseModelBaseModel = { +export type PropertyTypeModelBaseModel = { id?: string; containerId?: string | null; sortOrder?: number; diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/SetTourStatusRequestModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/SetTourStatusRequestModel.ts new file mode 100644 index 0000000000..258d0301e4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/SetTourStatusRequestModel.ts @@ -0,0 +1,8 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { TourStatusModel } from './TourStatusModel'; + +export type SetTourStatusRequestModel = TourStatusModel; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TourStatusModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TourStatusModel.ts new file mode 100644 index 0000000000..040fada99e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/TourStatusModel.ts @@ -0,0 +1,10 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type TourStatusModel = { + alias?: string; + completed?: boolean; + disabled?: boolean; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateContentTypeRequestModelBaseUpdateDocumentTypePropertyTypeRequestModelUpdateDocumentTypePropertyTypeContainerRequestModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateContentTypeRequestModelBaseUpdateDocumentTypePropertyTypeRequestModelUpdateDocumentTypePropertyTypeContainerRequestModel.ts new file mode 100644 index 0000000000..0388091f76 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateContentTypeRequestModelBaseUpdateDocumentTypePropertyTypeRequestModelUpdateDocumentTypePropertyTypeContainerRequestModel.ts @@ -0,0 +1,24 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { ContentTypeCompositionModel } from './ContentTypeCompositionModel'; +import type { ContentTypeSortModel } from './ContentTypeSortModel'; +import type { UpdateDocumentTypePropertyTypeContainerRequestModel } from './UpdateDocumentTypePropertyTypeContainerRequestModel'; +import type { UpdateDocumentTypePropertyTypeRequestModel } from './UpdateDocumentTypePropertyTypeRequestModel'; + +export type UpdateContentTypeRequestModelBaseUpdateDocumentTypePropertyTypeRequestModelUpdateDocumentTypePropertyTypeContainerRequestModel = { + alias?: string; + name?: string; + description?: string | null; + icon?: string; + allowedAsRoot?: boolean; + variesByCulture?: boolean; + variesBySegment?: boolean; + isElement?: boolean; + properties?: Array; + containers?: Array; + allowedContentTypes?: Array; + compositions?: Array; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateDocumentTypePropertyTypeContainerRequestModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateDocumentTypePropertyTypeContainerRequestModel.ts new file mode 100644 index 0000000000..fefe7b4724 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateDocumentTypePropertyTypeContainerRequestModel.ts @@ -0,0 +1,8 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { PropertyTypeContainerModelBaseModel } from './PropertyTypeContainerModelBaseModel'; + +export type UpdateDocumentTypePropertyTypeContainerRequestModel = PropertyTypeContainerModelBaseModel; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateDocumentTypePropertyTypeRequestModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateDocumentTypePropertyTypeRequestModel.ts new file mode 100644 index 0000000000..f1ee08ec0c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateDocumentTypePropertyTypeRequestModel.ts @@ -0,0 +1,8 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { PropertyTypeModelBaseModel } from './PropertyTypeModelBaseModel'; + +export type UpdateDocumentTypePropertyTypeRequestModel = PropertyTypeModelBaseModel; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateDocumentTypeRequestModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateDocumentTypeRequestModel.ts new file mode 100644 index 0000000000..b1b531f34c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UpdateDocumentTypeRequestModel.ts @@ -0,0 +1,14 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { ContentTypeCleanupModel } from './ContentTypeCleanupModel'; +import type { UpdateContentTypeRequestModelBaseUpdateDocumentTypePropertyTypeRequestModelUpdateDocumentTypePropertyTypeContainerRequestModel } from './UpdateContentTypeRequestModelBaseUpdateDocumentTypePropertyTypeRequestModelUpdateDocumentTypePropertyTypeContainerRequestModel'; + +export type UpdateDocumentTypeRequestModel = (UpdateContentTypeRequestModelBaseUpdateDocumentTypePropertyTypeRequestModelUpdateDocumentTypePropertyTypeContainerRequestModel & { + $type: string; + allowedTemplateIds?: Array; + defaultTemplateId?: string | null; + cleanup?: ContentTypeCleanupModel; +}); + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UserDataModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UserDataModel.ts new file mode 100644 index 0000000000..60d514bb23 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UserDataModel.ts @@ -0,0 +1,9 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type UserDataModel = { + name?: string; + data?: string; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UserDataResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UserDataResponseModel.ts new file mode 100644 index 0000000000..a32928d58f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UserDataResponseModel.ts @@ -0,0 +1,10 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { UserDataModel } from './UserDataModel'; + +export type UserDataResponseModel = { + userData?: Array; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UserPermissionModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UserPermissionModel.ts new file mode 100644 index 0000000000..c003edb1b3 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UserPermissionModel.ts @@ -0,0 +1,9 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +export type UserPermissionModel = { + nodeKey?: string; + permissions?: Array; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UserPermissionsResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UserPermissionsResponseModel.ts new file mode 100644 index 0000000000..9d2e3003e2 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UserPermissionsResponseModel.ts @@ -0,0 +1,10 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { UserPermissionModel } from './UserPermissionModel'; + +export type UserPermissionsResponseModel = { + permissions?: Array; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UserTourStatusesResponseModel.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UserTourStatusesResponseModel.ts new file mode 100644 index 0000000000..caad81eec0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/models/UserTourStatusesResponseModel.ts @@ -0,0 +1,11 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { SetTourStatusRequestModel } from './SetTourStatusRequestModel'; +import type { TourStatusModel } from './TourStatusModel'; + +export type UserTourStatusesResponseModel = { + tourStatuses?: Array<(TourStatusModel | SetTourStatusRequestModel)>; +}; + diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentTypeResource.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentTypeResource.ts index 430d840e9d..775098175e 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentTypeResource.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/DocumentTypeResource.ts @@ -1,9 +1,11 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ +import type { CreateDocumentTypeRequestModel } from '../models/CreateDocumentTypeRequestModel'; import type { DocumentTypeItemResponseModel } from '../models/DocumentTypeItemResponseModel'; import type { DocumentTypeResponseModel } from '../models/DocumentTypeResponseModel'; import type { PagedDocumentTypeTreeItemResponseModel } from '../models/PagedDocumentTypeTreeItemResponseModel'; +import type { UpdateDocumentTypeRequestModel } from '../models/UpdateDocumentTypeRequestModel'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; @@ -11,6 +13,28 @@ import { request as __request } from '../core/request'; export class DocumentTypeResource { + /** + * @returns any Success + * @throws ApiError + */ + public static postDocumentType({ + requestBody, + }: { + requestBody?: CreateDocumentTypeRequestModel, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/umbraco/management/api/v1/document-type', + body: requestBody, + mediaType: 'application/json', + responseHeader: 'location', + errors: { + 400: `Bad Request`, + 404: `Not Found`, + }, + }); + } + /** * @returns any Success * @throws ApiError @@ -32,6 +56,53 @@ export class DocumentTypeResource { }); } + /** + * @returns any Success + * @throws ApiError + */ + public static deleteDocumentTypeById({ + id, + }: { + id: string, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'DELETE', + url: '/umbraco/management/api/v1/document-type/{id}', + path: { + 'id': id, + }, + errors: { + 404: `Not Found`, + }, + }); + } + + /** + * @returns any Success + * @throws ApiError + */ + public static putDocumentTypeById({ + id, + requestBody, + }: { + id: string, + requestBody?: UpdateDocumentTypeRequestModel, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'PUT', + url: '/umbraco/management/api/v1/document-type/{id}', + path: { + 'id': id, + }, + body: requestBody, + mediaType: 'application/json', + errors: { + 400: `Bad Request`, + 404: `Not Found`, + }, + }); + } + /** * @returns any Success * @throws ApiError diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/TourResource.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/TourResource.ts new file mode 100644 index 0000000000..8a020fc73c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/TourResource.ts @@ -0,0 +1,41 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { SetTourStatusRequestModel } from '../models/SetTourStatusRequestModel'; +import type { UserTourStatusesResponseModel } from '../models/UserTourStatusesResponseModel'; + +import type { CancelablePromise } from '../core/CancelablePromise'; +import { OpenAPI } from '../core/OpenAPI'; +import { request as __request } from '../core/request'; + +export class TourResource { + + /** + * @returns any Success + * @throws ApiError + */ + public static getTour(): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/tour', + }); + } + + /** + * @returns any Success + * @throws ApiError + */ + public static postTour({ + requestBody, + }: { + requestBody?: SetTourStatusRequestModel, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/umbraco/management/api/v1/tour', + body: requestBody, + mediaType: 'application/json', + }); + } + +} diff --git a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/UserResource.ts b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/UserResource.ts index 028ea7bd6e..6680b0ac4c 100644 --- a/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/UserResource.ts +++ b/src/Umbraco.Web.UI.Client/src/external/backend-api/src/services/UserResource.ts @@ -4,17 +4,21 @@ import type { ChangePasswordUserRequestModel } from '../models/ChangePasswordUserRequestModel'; import type { CreateUserRequestModel } from '../models/CreateUserRequestModel'; import type { CreateUserResponseModel } from '../models/CreateUserResponseModel'; +import type { CurrentUserResponseModel } from '../models/CurrentUserResponseModel'; import type { DirectionModel } from '../models/DirectionModel'; import type { DisableUserRequestModel } from '../models/DisableUserRequestModel'; import type { EnableUserRequestModel } from '../models/EnableUserRequestModel'; import type { InviteUserRequestModel } from '../models/InviteUserRequestModel'; +import type { LinkedLoginsRequestModel } from '../models/LinkedLoginsRequestModel'; import type { PagedUserResponseModel } from '../models/PagedUserResponseModel'; import type { SetAvatarRequestModel } from '../models/SetAvatarRequestModel'; import type { UnlockUsersRequestModel } from '../models/UnlockUsersRequestModel'; import type { UpdateUserGroupsOnUserRequestModel } from '../models/UpdateUserGroupsOnUserRequestModel'; import type { UpdateUserRequestModel } from '../models/UpdateUserRequestModel'; +import type { UserDataResponseModel } from '../models/UserDataResponseModel'; import type { UserItemResponseModel } from '../models/UserItemResponseModel'; import type { UserOrderModel } from '../models/UserOrderModel'; +import type { UserPermissionsResponseModel } from '../models/UserPermissionsResponseModel'; import type { UserResponseModel } from '../models/UserResponseModel'; import type { UserStateModel } from '../models/UserStateModel'; @@ -191,6 +195,127 @@ export class UserResource { }); } + /** + * @returns any Success + * @throws ApiError + */ + public static getUserCurrent(): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/user/current', + }); + } + + /** + * @returns any Success + * @throws ApiError + */ + public static postUserCurrentAvatar({ + requestBody, + }: { + requestBody?: SetAvatarRequestModel, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/umbraco/management/api/v1/user/current/avatar', + body: requestBody, + mediaType: 'application/json', + }); + } + + /** + * @returns any Success + * @throws ApiError + */ + public static postUserCurrentChangePassword({ + requestBody, + }: { + requestBody?: ChangePasswordUserRequestModel, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/umbraco/management/api/v1/user/current/change-password', + body: requestBody, + mediaType: 'application/json', + }); + } + + /** + * @returns any Success + * @throws ApiError + */ + public static getUserCurrentData(): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/user/current/data', + }); + } + + /** + * @returns any Success + * @throws ApiError + */ + public static getUserCurrentLogins(): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/user/current/logins', + }); + } + + /** + * @returns any Success + * @throws ApiError + */ + public static getUserCurrentPermissions({ + id, + }: { + id?: Array, + }): CancelablePromise> { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/user/current/permissions', + query: { + 'id': id, + }, + }); + } + + /** + * @returns any Success + * @throws ApiError + */ + public static getUserCurrentPermissionsDocument({ + id, + }: { + id?: Array, + }): CancelablePromise> { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/user/current/permissions/document', + query: { + 'id': id, + }, + }); + } + + /** + * @returns any Success + * @throws ApiError + */ + public static getUserCurrentPermissionsMedia({ + id, + }: { + id?: Array, + }): CancelablePromise> { + return __request(OpenAPI, { + method: 'GET', + url: '/umbraco/management/api/v1/user/current/permissions/media', + query: { + 'id': id, + }, + }); + } + /** * @returns any Success * @throws ApiError diff --git a/src/Umbraco.Web.UI.Client/src/libs/context-api/provide/context-provider.ts b/src/Umbraco.Web.UI.Client/src/libs/context-api/provide/context-provider.ts index bd7632f47c..add39e4e26 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/context-api/provide/context-provider.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/context-api/provide/context-provider.ts @@ -86,6 +86,6 @@ export class UmbContextProvider { destroy(): void { // I want to make sure to call this, but for now it was too overwhelming to require the destroy method on context instances. - (this.#instance as any).destroy?.(); + (this.#instance as any)?.destroy?.(); } } diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/document-type.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/document-type.data.ts index f6644b4aed..f2ede5c6bb 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/document-type.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/document-type.data.ts @@ -1110,26 +1110,46 @@ class UmbDocumentTypeData extends UmbEntityData { super(data); } + // TODO: Can we do this smarter so we don't need to make this for each mock data: + insert(item: DocumentTypeResponseModel) { + const result = super.insert(item); + this.treeData.push(createDocumentTypeTreeItem(result)); + return result; + } + + update(item: DocumentTypeResponseModel) { + const result = super.save(item); + this.treeData = this.treeData.map((x) => { + if(x.id === result.id) { + return createDocumentTypeTreeItem(result); + } else { + return x; + } + }); + return result; + } + getTreeRoot(): Array { const rootItems = this.treeData.filter((item) => item.parentId === null); - return rootItems.map((item) => createDocumentTypeTreeItem(item)); + const result = rootItems.map((item) => createDocumentTypeTreeItem(item)); + return result; } getTreeItemChildren(id: string): Array { const childItems = this.treeData.filter((item) => item.parentId === id); - return childItems.map((item) => createDocumentTypeTreeItem(item)); + return childItems.map((item) => item); } getTreeItem(ids: Array): Array { const items = this.treeData.filter((item) => ids.includes(item.id ?? '')); - return items.map((item) => createDocumentTypeTreeItem(item)); + return items.map((item) => item); } getAllowedTypesOf(id: string): Array { const documentType = this.getById(id); const allowedTypeKeys = documentType?.allowedContentTypes?.map((documentType) => documentType.id) ?? []; const items = this.treeData.filter((item) => allowedTypeKeys.includes(item.id ?? '')); - return items.map((item) => createDocumentTypeTreeItem(item)); + return items.map((item) => item); } } diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/document.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/document.data.ts index 04ad43b8ce..88034aeb39 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/document.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/document.data.ts @@ -618,23 +618,42 @@ class UmbDocumentData extends UmbEntityData { super(data); } + // TODO: Can we do this smarter so we don't need to make this for each mock data: + insert(item: DocumentResponseModel) { + const result = super.insert(item); + this.treeData.push(createDocumentTreeItem(result)); + return result; + } + + update(item: DocumentResponseModel) { + const result = super.save(item); + this.treeData = this.treeData.map((x) => { + if(x.id === result.id) { + return createDocumentTreeItem(result); + } else { + return x; + } + }); + return result; + } + getTreeRoot(): PagedDocumentTreeItemResponseModel { const items = this.treeData.filter((item) => item.parentId === null); - const treeItems = items.map((item) => createDocumentTreeItem(item)); + const treeItems = items.map((item) => item); const total = items.length; return { items: treeItems, total }; } getTreeItemChildren(id: string): PagedDocumentTreeItemResponseModel { const items = this.treeData.filter((item) => item.parentId === id); - const treeItems = items.map((item) => createDocumentTreeItem(item)); + const treeItems = items.map((item) => item); const total = items.length; return { items: treeItems, total }; } getTreeItem(ids: Array): Array { const items = this.treeData.filter((item) => ids.includes(item.id ?? '')); - return items.map((item) => createDocumentTreeItem(item)); + return items.map((item) => item); } } diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/entity.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/entity.data.ts index cbab9f2207..11f2d98ff5 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/entity.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/entity.data.ts @@ -1,4 +1,5 @@ import { UmbData } from './data.js'; +import { UmbId } from '@umbraco-cms/backoffice/id'; import type { UmbEntityBase } from '@umbraco-cms/backoffice/models'; // Temp mocked database @@ -23,6 +24,12 @@ export class UmbEntityData extends UmbData { } insert(item: T) { + + // TODO: Remove this fix when all types come with an ID them selfs. + if (!item.id) { + item.id = UmbId.new(); + } + const exits = this.data.find((i) => i.id === item.id); if (exits) { @@ -30,6 +37,8 @@ export class UmbEntityData extends UmbData { } this.data.push(item); + + return item; } save(saveItem: T) { diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/utils.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/utils.ts index f6a4e102ee..a2549cc2ae 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/utils.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/utils.ts @@ -6,6 +6,7 @@ import type { FolderTreeItemResponseModel, DocumentTypeResponseModel, FileSystemTreeItemPresentationModel, + DocumentResponseModel, } from '@umbraco-cms/backoffice/backend-api'; export const createEntityTreeItem = (item: any): EntityTreeItemResponseModel => { @@ -17,7 +18,7 @@ export const createEntityTreeItem = (item: any): EntityTreeItemResponseModel => hasChildren: item.hasChildren, id: item.id, isContainer: item.isContainer, - parentId: item.parentId, + parentId: item.parentId ?? null, }; }; @@ -31,6 +32,7 @@ export const createFolderTreeItem = (item: any): FolderTreeItemResponseModel => // TODO: remove isTrashed type extension when we have found a solution to trashed items export const createContentTreeItem = (item: any): ContentTreeItemResponseModel & { isTrashed: boolean } => { + // TODO: There we have to adapt to variants as part of the tree model: return { ...createEntityTreeItem(item), noAccess: item.noAccess, @@ -40,23 +42,28 @@ export const createContentTreeItem = (item: any): ContentTreeItemResponseModel & // TODO: remove isTrashed type extension when we have found a solution to trashed items export const createDocumentTreeItem = ( - item: DocumentTreeItemResponseModel + item: DocumentResponseModel ): DocumentTreeItemResponseModel & { isTrashed: boolean } => { return { ...createContentTreeItem(item), - /* - noAccess: item.noAccess, - isProtected: item.isProtected, - isPublished: item.isPublished, - isEdited: item.isEdited, - isTrashed: item.isTrashed, - */ + $type: "DocumentTreeItemViewModel", + type: "document", + icon: "document",// TODO: Should get this from document type... + name: item.variants?.[0].name ?? '', + noAccess: false, + isProtected: false, + isPublished: false, + isEdited: false, + isTrashed: false, + hasChildren: false, + isContainer: false, }; }; export const createDocumentTypeTreeItem = (item: DocumentTypeResponseModel): DocumentTypeTreeItemResponseModel => { return { - ...createFolderTreeItem(item), + ...createEntityTreeItem(item), + type: "document-type", isElement: item.isElement, }; }; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/handlers/document-type.handlers.ts b/src/Umbraco.Web.UI.Client/src/mocks/handlers/document-type.handlers.ts index 1eb99efaea..46a8a93512 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/handlers/document-type.handlers.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/handlers/document-type.handlers.ts @@ -9,9 +9,13 @@ export const handlers = [ const data = await req.json(); if (!data) return; - umbDocumentTypeData.insert(data); + // TODO: This is something that is missing in the Full model, but which we need to for the tree model. This should be fixed in the Full model. + data.parentId ??= null; - return res(ctx.status(200)); + const created = umbDocumentTypeData.insert(data); + + // TODO: remove this hack, as we get the right end-point, in that case we will be in control of the Ids. (I choose this URL to make it clear thats its a hack/mocked URL) + return res(ctx.status(200), ctx.set({'location': '/header/location/id/'+created.id})); }), rest.put(umbracoPath(`/document-type/:id`), async (req, res, ctx) => { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/property-type-based-property/property-type-based-property.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/property-type-based-property/property-type-based-property.element.ts index a5fec24cb1..bf47e156e8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/property-type-based-property/property-type-based-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/property-type-based-property/property-type-based-property.element.ts @@ -6,7 +6,7 @@ import type { UmbVariantId } from '@umbraco-cms/backoffice/variant'; import type { DataTypeResponseModel, DataTypePropertyPresentationModel, - PropertyTypeResponseModelBaseModel, + PropertyTypeModelBaseModel, } from '@umbraco-cms/backoffice/backend-api'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; @@ -15,10 +15,10 @@ import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registr @customElement('umb-property-type-based-property') export class UmbPropertyTypeBasedPropertyElement extends UmbLitElement { @property({ type: Object, attribute: false }) - public get property(): PropertyTypeResponseModelBaseModel | undefined { + public get property(): PropertyTypeModelBaseModel | undefined { return this._property; } - public set property(value: PropertyTypeResponseModelBaseModel | undefined) { + public set property(value: PropertyTypeModelBaseModel | undefined) { const oldProperty = this._property; this._property = value; if (this._property?.dataTypeId !== oldProperty?.dataTypeId) { @@ -26,7 +26,7 @@ export class UmbPropertyTypeBasedPropertyElement extends UmbLitElement { this._observeProperty(); } } - private _property?: PropertyTypeResponseModelBaseModel; + private _property?: PropertyTypeModelBaseModel; @state() private _propertyEditorUiAlias?: string; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-container-structure-helper.class.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-container-structure-helper.class.ts index b754338ad5..c186b6f312 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-container-structure-helper.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-container-structure-helper.class.ts @@ -2,7 +2,7 @@ import { PropertyContainerTypes, UmbContentTypePropertyStructureManager, } from './content-type-structure-manager.class.js'; -import { PropertyTypeContainerResponseModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; +import { PropertyTypeContainerModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; import { UmbArrayState, UmbBooleanState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; @@ -20,12 +20,12 @@ export class UmbContentTypeContainerStructureHelper { // Containers defined in data might be more than actual containers to display as we merge them by name. // Direct containers are the containers defining the total of this container(Multiple containers with the same name and type) - private _directContainers: PropertyTypeContainerResponseModelBaseModel[] = []; + private _directContainers: PropertyTypeContainerModelBaseModel[] = []; // Owner containers are containers owned by the owner Document Type (The specific one up for editing) - private _ownerContainers: PropertyTypeContainerResponseModelBaseModel[] = []; + private _ownerContainers: PropertyTypeContainerModelBaseModel[] = []; // State containing the merged containers (only one pr. name): - #containers = new UmbArrayState([], (x) => x.id); + #containers = new UmbArrayState([], (x) => x.id); readonly containers = this.#containers.asObservable(); #hasProperties = new UmbBooleanState(false); @@ -159,7 +159,7 @@ export class UmbContentTypeContainerStructureHelper { ); } - private _insertGroupContainers = (groupContainers: PropertyTypeContainerResponseModelBaseModel[]) => { + private _insertGroupContainers = (groupContainers: PropertyTypeContainerModelBaseModel[]) => { groupContainers.forEach((group) => { if (group.name !== null && group.name !== undefined) { if (!this.#containers.getValue().find((x) => x.name === group.name)) { @@ -188,7 +188,7 @@ export class UmbContentTypeContainerStructureHelper { async partialUpdateContainer( containerId?: string, - partialUpdate?: Partial + partialUpdate?: Partial ) { await this.#init; if (!this.#structure || !containerId || !partialUpdate) return; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-property-structure-helper.class.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-property-structure-helper.class.ts index 32efa3ce21..94ba91de59 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-property-structure-helper.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-property-structure-helper.class.ts @@ -4,7 +4,7 @@ import { } from './content-type-structure-manager.class.js'; import { DocumentTypePropertyTypeResponseModel, - PropertyTypeResponseModelBaseModel, + PropertyTypeModelBaseModel, } from '@umbraco-cms/backoffice/backend-api'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; import { UmbArrayState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; @@ -116,7 +116,7 @@ export class UmbContentTypePropertyStructureHelper { return await this.#structure.createProperty(null, ownerId, sortOrder); } - async insertProperty(property: PropertyTypeResponseModelBaseModel, sortOrder = 0) { + async insertProperty(property: PropertyTypeModelBaseModel, sortOrder = 0) { await this.#init; if (!this.#structure) return false; @@ -139,7 +139,6 @@ export class UmbContentTypePropertyStructureHelper { async partialUpdateProperty(propertyKey?: string, partialUpdate?: Partial) { await this.#init; if (!this.#structure || !propertyKey || !partialUpdate) return; - return await this.#structure.updateProperty(null, propertyKey, partialUpdate); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-structure-manager.class.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-structure-manager.class.ts index d76840aea6..248c0eb6bd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-structure-manager.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-structure-manager.class.ts @@ -2,8 +2,8 @@ import { UmbDetailRepository } from '@umbraco-cms/backoffice/repository'; import { UmbId } from '@umbraco-cms/backoffice/id'; import { DocumentTypePropertyTypeResponseModel, - PropertyTypeContainerResponseModelBaseModel, - PropertyTypeResponseModelBaseModel, + PropertyTypeContainerModelBaseModel, + PropertyTypeModelBaseModel, DocumentTypeResponseModel, } from '@umbraco-cms/backoffice/backend-api'; import { UmbControllerHostElement, UmbControllerInterface } from '@umbraco-cms/backoffice/controller-api'; @@ -35,7 +35,7 @@ export class UmbContentTypePropertyStructureManager x.containers ?? []) ); - #containers = new UmbArrayState([], (x) => x.id); + #containers = new UmbArrayState([], (x) => x.id); constructor(host: UmbControllerHostElement, typeRepository: R) { this.#host = host; @@ -95,7 +95,12 @@ export class UmbContentTypePropertyStructureManager + partialUpdate: Partial ) { await this.#init; documentTypeId = documentTypeId ?? this.#ownerDocumentTypeId!; @@ -216,7 +221,7 @@ export class UmbContentTypePropertyStructureManager + partialUpdate: Partial ) { await this.#init; documentTypeId = documentTypeId ?? this.#ownerDocumentTypeId!; @@ -349,7 +354,7 @@ export class UmbContentTypePropertyStructureManager { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/delete/delete.action.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/delete/delete.action.ts index 3f91a4e0b1..9f6d111f40 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/delete/delete.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/common/delete/delete.action.ts @@ -11,25 +11,25 @@ import { UmbDetailRepository, UmbItemRepository } from '@umbraco-cms/backoffice/ export class UmbDeleteEntityAction< T extends UmbDetailRepository & UmbItemRepository > extends UmbEntityActionBase { - #modalContext?: UmbModalManagerContext; + #modalManager?: UmbModalManagerContext; constructor(host: UmbControllerHostElement, repositoryAlias: string, unique: string) { super(host, repositoryAlias, unique); new UmbContextConsumerController(this.host, UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => { - this.#modalContext = instance; + this.#modalManager = instance; }); } async execute() { - if (!this.repository || !this.#modalContext) return; + if (!this.repository || !this.#modalManager) return; const { data } = await this.repository.requestItems([this.unique]); if (data) { const item = data[0]; - const modalContext = this.#modalContext.open(UMB_CONFIRM_MODAL, { + const modalContext = this.#modalManager.open(UMB_CONFIRM_MODAL, { headline: `Delete ${item.name}`, content: 'Are you sure you want to delete this item?', color: 'danger', diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/property-settings/property-settings-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/property-settings/property-settings-modal.element.ts index 38efddb9e6..7cc4e54ca4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/property-settings/property-settings-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/property-settings/property-settings-modal.element.ts @@ -15,6 +15,7 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< UmbPropertySettingsModalResult > { //TODO: Should these options come from the server? + // TODO: Or should they come from a extension point? @state() private _customValidationOptions = [ { name: 'No validation', @@ -44,15 +45,14 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< @state() protected _returnData!: UmbPropertySettingsModalResult; - constructor() { - super(); - } connectedCallback(): void { super.connectedCallback(); this._returnData = JSON.parse(JSON.stringify(this.data)); - const regEx = this._returnData.validation?.regEx ?? ''; + this._returnData.validation ??= {}; + + const regEx = this._returnData.validation.regEx ?? ''; const newlySelected = this._customValidationOptions.find((option) => { option.selected = option.value === regEx; return option.selected; @@ -80,10 +80,6 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< const isValid = form.checkValidity(); if (!isValid) return; - const formData = new FormData(form); - - this._returnData.validation!.mandatoryMessage = formData.get('mandatory-message')?.toString() || ''; - this.modalContext?.submit(this._returnData); } @@ -152,11 +148,6 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< #onToggleAliasLock() { this._aliasLocked = !this._aliasLocked; - - if (this._aliasLocked) { - this._returnData.alias = generateAlias(this._returnData.alias ?? ''); - this.requestUpdate('_returnData'); - } } #onValidationRegExChange(event: UUIInputEvent) { @@ -238,34 +229,32 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< } #renderAlignLeftIcon() { - return html`
''} class="appearance left ${this._returnData.appearance?.labelOnTop ? '' : 'selected'}"> - - - - - + + + + -
`; + `; } #renderAlignTopIcon() { return html` -
''} class="appearance top ${this._returnData.appearance?.labelOnTop ? 'selected' : ''}"> - - - - - + + + + -
+ `; } @@ -328,10 +317,11 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< .appearance { position: relative; display: flex; - border: 2px solid var(--uui-color-border-standalone); + border: 1px solid var(--uui-color-border-standalone); + background-color: transparent; padding: var(--uui-size-space-4) var(--uui-size-space-5); align-items: center; - border-radius: 6px; + border-radius: var(--uui-border-radius); opacity: 0.8; flex-direction: column; justify-content: space-between; @@ -340,26 +330,8 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< .appearance-label { font-size: 0.8rem; line-height: 1; - } - .appearance.selected .appearance-label { font-weight: bold; - } - .appearance:not(.selected):hover { - border-color: var(--uui-color-border-emphasis); - cursor: pointer; - opacity: 1; - } - .appearance.selected { - border-color: var(--uui-color-selected); - opacity: 1; - } - .appearance.selected::after { - content: ''; - position: absolute; - inset: 0; - border-radius: 6px; - opacity: 0.1; - background-color: var(--uui-color-selected); + pointer-events: none; } .appearance.left { flex-grow: 1; @@ -372,6 +344,28 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< width: 100%; color: var(--uui-color-text); } + .appearance:not(.selected):hover { + border-color: var(--uui-color-border-emphasis); + cursor: pointer; + opacity: 1; + } + .appearance.selected { + background-color: var(--uui-color-surface); + border-color: var(--uui-color-selected); + color: var(--uui-color-selected); + opacity: 1; + } + .appearance.selected svg { + color: var(--uui-color-selected); + } + .appearance.selected::after { + content: ''; + position: absolute; + inset: 0; + border-radius: 6px; + opacity: 0.1; + background-color: var(--uui-color-selected); + } hr { border: none; border-top: 1px solid var(--uui-color-divider); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal-context.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal-context.ts index 111da254d7..c1b31644d8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal-context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal-context.ts @@ -11,10 +11,10 @@ import { BehaviorSubject } from '@umbraco-cms/backoffice/external/rxjs'; import { ManifestModal, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; import type { UmbRouterSlotElement } from '@umbraco-cms/backoffice/router'; import { createExtensionElement } from '@umbraco-cms/backoffice/extension-api'; -import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; +import type { UmbControllerHostElement, UmbControllerInterface } from '@umbraco-cms/backoffice/controller-api'; import { UmbId } from '@umbraco-cms/backoffice/id'; import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; -import { UmbContextProviderController, UmbContextToken } from '@umbraco-cms/backoffice/context-api'; +import { UmbContextProvider, UmbContextToken } from '@umbraco-cms/backoffice/context-api'; /** * Type which omits the real submit method, and replaces it with a submit method which accepts an optional argument depending on the generic type. @@ -41,15 +41,17 @@ type OptionalSubmitArgumentIfUndefined = T extends undefined }; // TODO: consider splitting this into two separate handlers -export class UmbModalContextClass { +export class UmbModalContextClass implements UmbControllerInterface { #host: UmbControllerHostElement; #submitPromise: Promise; #submitResolver?: (value: ModalResult) => void; #submitRejecter?: () => void; + private _modalExtensionObserver?: UmbObserverController; public readonly modalElement: UUIModalDialogElement | UUIModalSidebarElement; #modalRouterElement: UmbRouterSlotElement = document.createElement('umb-router-slot'); + #modalContextProvider; #innerElement = new BehaviorSubject(undefined); public readonly innerElement = this.#innerElement.asObservable(); @@ -59,6 +61,10 @@ export class UmbModalContextClass ); + + this.#host.addController(this); + } + + hostConnected(): void { + this.#modalContextProvider.hostConnected(); + } + hostDisconnected(): void { + this.#modalContextProvider.hostDisconnected(); } #createContainerElement() { @@ -139,7 +156,8 @@ export class UmbModalContextClass { @@ -150,8 +168,7 @@ export class UmbModalContextClass { return this.#submitPromise; } + + + + destroy(): void { + this.#innerElement.complete(); + this._modalExtensionObserver?.destroy(); + this._modalExtensionObserver = undefined; + } } export const UMB_MODAL_CONTEXT_TOKEN = new UmbContextToken('UmbModalContext'); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal-route-registration.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal-route-registration.controller.ts index 88fd59ce9c..274ff8b6ac 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal-route-registration.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/modal-route-registration.controller.ts @@ -108,6 +108,9 @@ export class UmbModalRouteRegistrationController implements UmbControllerInterface { hostDisconnected() { // TODO: Clean up?? this.#observer.disconnect(); - (this.#containerElement as any)['__umbBlockGridSorterController'] = undefined; - this.#containerElement.removeEventListener('dragover', preventDragOver); - (this.#containerElement as any) = undefined; + if(this.#containerElement) { + (this.#containerElement as any)['__umbBlockGridSorterController'] = undefined; + this.#containerElement.removeEventListener('dragover', preventDragOver); + (this.#containerElement as any) = undefined; + } } setupItem(element: HTMLElement) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-base/tree-item-base.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-base/tree-item-base.element.ts index 4297852298..7471f61c93 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-base/tree-item-base.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree-item-base/tree-item-base.element.ts @@ -76,7 +76,9 @@ export class UmbTreeItemBaseElement extends UmbLitElement { if (!asObservable) return; this.observe(asObservable(), (childItems) => { + const oldValue = this._childItems; this._childItems = childItems; + this.requestUpdate('_childItems', oldValue); }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree.element.ts index 94b1e6125a..7767b2e50d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/tree/tree.element.ts @@ -42,7 +42,7 @@ export class UmbTreeElement extends UmbLitElement { this.#treeContext.setMultiple(newVal); } - // TODO: what is the best name for this functionatliy? + // TODO: what is the best name for this functionality? private _hideTreeRoot = false; @property({ type: Boolean, attribute: 'hide-tree-root' }) get hideTreeRoot() { @@ -96,8 +96,9 @@ export class UmbTreeElement extends UmbLitElement { if (asObservable) { this.#rootItemsObserver = this.observe(asObservable(), (rootItems) => { + const oldValue = this._items; this._items = rootItems; - this.requestUpdate(); + this.requestUpdate('_items', oldValue); }); } } @@ -116,7 +117,8 @@ export class UmbTreeElement extends UmbLitElement { return html` ${repeat( this._items, - (item, index) => index, + // TODO: use unique here: + (item, index) => item.name + '___' + index, (item) => html`` )} `; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/variant/variant-id.class.ts b/src/Umbraco.Web.UI.Client/src/packages/core/variant/variant-id.class.ts index d8e07d72d0..591731aa49 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/variant/variant-id.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/variant/variant-id.class.ts @@ -7,12 +7,12 @@ export class UmbVariantId { public readonly segment: string | null = null; constructor(variantData: { culture?: string | null; segment?: string | null }) { - this.culture = variantData.culture || null; - this.segment = variantData.segment || null; + this.culture = (variantData.culture === 'invariant' ? null : variantData.culture) ?? null; + this.segment = variantData.segment ?? null; } public compare(obj: { culture?: string | null; segment?: string | null }): boolean { - return this.culture === (obj.culture || null) && this.segment === (obj.segment || null); + return this.equal(new UmbVariantId(obj)); } public equal(variantId: UmbVariantId): boolean { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-footer/workspace-footer.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-footer/workspace-footer.element.ts index dd6c99aa09..5e6822afa3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-footer/workspace-footer.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-footer/workspace-footer.element.ts @@ -41,17 +41,18 @@ export class UmbWorkspaceFooterLayoutElement extends UmbLitElement { @state() _withinModal = false; - #modalContext?: UmbModalContext; + @state() + _modalContext?: UmbModalContext; constructor() { super(); this.consumeContext(UMB_MODAL_CONTEXT_TOKEN, (context) => { - this.#modalContext = context; + this._modalContext = context; }); } private _onClose = () => { - this.#modalContext?.reject(); + this._modalContext?.reject(); }; // TODO: Some event/callback from umb-extension-slot that can be utilized to hide the footer, if empty. @@ -59,10 +60,10 @@ export class UmbWorkspaceFooterLayoutElement extends UmbLitElement { return html` - - ${this.#modalContext + ${this._modalContext ? html`` : ''} + { + new UmbObserverController(host, this.#index, () => { this._observeVariant(); }); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/manifests.ts index 7ab1073034..8df1b50274 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/manifests.ts @@ -3,7 +3,7 @@ import { manifests as createManifests } from './create/manifests.js'; import { UmbCopyEntityAction, UmbMoveEntityAction, - UmbTrashEntityAction, + UmbDeleteEntityAction, UmbSortChildrenOfEntityAction, } from '@umbraco-cms/backoffice/entity-action'; import { ManifestEntityAction } from '@umbraco-cms/backoffice/extension-registry'; @@ -13,14 +13,14 @@ const entityType = 'document-type'; const entityActions: Array = [ { type: 'entityAction', - alias: 'Umb.EntityAction.DocumentType.Trash', - name: 'Trash Document-Type Entity Action', + alias: 'Umb.EntityAction.DocumentType.Delete', + name: 'Delete Document-Type Entity Action', weight: 900, meta: { icon: 'umb:trash', - label: 'Trash', + label: 'Delete (TBD)', repositoryAlias: DOCUMENT_TYPE_REPOSITORY_ALIAS, - api: UmbTrashEntityAction, + api: UmbDeleteEntityAction, }, conditions: { entityTypes: [entityType], diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/modals/allowed-document-types/allowed-document-types-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/modals/allowed-document-types/allowed-document-types-modal.element.ts index ec849a09f3..a81630fd76 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/modals/allowed-document-types/allowed-document-types-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/modals/allowed-document-types/allowed-document-types-modal.element.ts @@ -3,7 +3,7 @@ import { html, nothing, customElement, state, ifDefined } from '@umbraco-cms/bac import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui'; import { UmbAllowedDocumentTypesModalData, UmbAllowedDocumentTypesModalResult } from '@umbraco-cms/backoffice/modal'; import { UmbModalBaseElement } from '@umbraco-cms/internal/modal'; -import { DocumentTypeTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { DocumentTypeResponseModel, DocumentTypeTreeItemResponseModel } from '@umbraco-cms/backoffice/backend-api'; @customElement('umb-allowed-document-types-modal') export class UmbAllowedDocumentTypesModalElement extends UmbModalBaseElement< @@ -21,17 +21,20 @@ export class UmbAllowedDocumentTypesModalElement extends UmbModalBaseElement< public connectedCallback() { super.connectedCallback(); + const parentId = this.data?.parentId; const parentName = this.data?.parentName; if (parentName) { this._headline = `Create at '${parentName}'`; } else { this._headline = `Create`; } - if (this.data?.parentId) { + if (parentId) { // TODO: Support root aka. id of null? or maybe its an active prop, like 'atRoot'. // TODO: show error - this._retrieveAllowedChildrenOf(this.data.parentId); + this._retrieveAllowedChildrenOf(parentId); + } else { + this._retrieveAllowedChildrenOfRoot(); } } @@ -43,6 +46,25 @@ export class UmbAllowedDocumentTypesModalElement extends UmbModalBaseElement< } } + private async _retrieveAllowedChildrenOfRoot() { + // TODO: This is a hack until we get the right end points (Which will become a Document end point. meaning this modal should have another name, it should be named so its clear that this is for documents, not document types. ex.: 'create-document-modal') + const { data } = await this.#documentTypeRepository.requestRootTreeItems(); + if (!data) return; + + const allFullModels: Array = []; + await Promise.all( + data.items.map((item) => { + if (item.id) { + return this.#documentTypeRepository.requestById(item.id).then((result) => {if(result.data) {allFullModels.push({$type: '', ...result.data})}}); + } + return Promise.resolve(); + }) + ); + + this._allowedDocumentTypes = allFullModels.filter((item) => item.allowedAsRoot) ?? []; + // End of hack...^^ + } + private _handleCancel() { this.modalContext?.reject(); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/document-type.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/document-type.repository.ts index bc7189bad8..512eed6d57 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/document-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/document-type.repository.ts @@ -6,16 +6,19 @@ import type { UmbTreeDataSource, UmbTreeRepository, UmbDetailRepository } from ' import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; import { + CreateDocumentTypeRequestModel, DocumentTypeResponseModel, EntityTreeItemResponseModel, FolderTreeItemResponseModel, + UpdateDocumentTypeRequestModel, } from '@umbraco-cms/backoffice/backend-api'; import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification'; -type ItemType = DocumentTypeResponseModel; +type ItemType = DocumentTypeResponseModel & {$type: string}; export class UmbDocumentTypeRepository - implements UmbTreeRepository, UmbDetailRepository + implements UmbTreeRepository, + UmbDetailRepository { #init!: Promise; @@ -131,6 +134,7 @@ export class UmbDocumentTypeRepository if (data) { this.#detailStore?.append(data); } + return { data }; } @@ -163,22 +167,38 @@ export class UmbDocumentTypeRepository // Could potentially be general methods: async create(documentType: ItemType) { + if (!documentType || !documentType.id) throw new Error('Template is missing'); await this.#init; - const { error } = await this.#detailDataSource.insert(documentType); + const { error, data } = await this.#detailDataSource.insert(documentType); - if (!error) { - const treeItem = createTreeItem(documentType); - this.#treeStore?.appendItems([treeItem]); + if (!error && data) { - const notification = { data: { message: `Document Type created` } }; - this.#notificationContext?.peek('positive', notification); + // TODO: The parts here is a hack, when we can trust the IDs we send, then this should be removed/changed: - // TODO: we currently don't use the detail store for anything. - // Consider to look up the data before fetching from the server - this.#detailStore?.append(documentType); - // TODO: Update tree store with the new item? or ask tree to request the new item? + const splitResultUrl = data.split("/"); + const newId = splitResultUrl[splitResultUrl.length - 1]; + + // Temporary hack while we are not in control of IDs: + + const newDocument = {...(await this.requestById(newId)).data, $type: ''}; + + if(newDocument) { + + const notification = { data: { message: `Document Type created` } }; + this.#notificationContext?.peek('positive', notification); + + await this.requestRootTreeItems(); + + // TODO: currently we cannot put this data into our store, cause we don't have the right ID, as the server currently changes it (and other ids of it, container-id and property-id) + //this.#detailStore?.append(newDocument); + + //const treeItem = createTreeItem(newDocument); + //this.#treeStore?.appendItems([treeItem]); + + return { data: newDocument }; + } } return { error }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/sources/document-type.server.data.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/sources/document-type.server.data.ts index 67d97db590..08fb043abe 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/sources/document-type.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/sources/document-type.server.data.ts @@ -1,5 +1,5 @@ import type { UmbDataSource } from '@umbraco-cms/backoffice/repository'; -import { DocumentTypeResource, DocumentTypeResponseModel } from '@umbraco-cms/backoffice/backend-api'; +import { CreateDocumentTypeRequestModel, DocumentTypeResource, DocumentTypeResponseModel, UpdateDocumentTypeRequestModel } from '@umbraco-cms/backoffice/backend-api'; import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; import { UmbId } from '@umbraco-cms/backoffice/id'; @@ -10,7 +10,7 @@ import { UmbId } from '@umbraco-cms/backoffice/id'; * @class UmbDocumentTypeServerDataSource * @implements {RepositoryDetailDataSource} */ -export class UmbDocumentTypeServerDataSource implements UmbDataSource { +export class UmbDocumentTypeServerDataSource implements UmbDataSource { #host: UmbControllerHostElement; /** @@ -48,8 +48,12 @@ export class UmbDocumentTypeServerDataSource implements UmbDataSource( + // TODO: Hack to remove some props that ruins the document-type post end-point. + (documentType as any).$type = undefined; + (documentType as any).id = undefined; + + // TODO: Investigate if this matters (should go away anyway when we have the end-point accepts us defining the ids.) + documentType.properties = documentType.properties?.map((prop) => { + return { + ...prop, + id: undefined, + } + }); + + return tryExecuteAndNotify( this.#host, - fetch('/umbraco/management/api/v1/document-type', { - method: 'POST', - body: body, - headers: { - 'Content-Type': 'application/json', - }, - }) as any + DocumentTypeResource.postDocumentType({ + requestBody: documentType, + }), ); } /** - * Updates a Document on the server - * @param {Document} Document + * Updates a Document Type on the server + * @param {string} id + * @param {Document} documentType * @return {*} * @memberof UmbDocumentTypeServerDataSource */ - async update(id: string, document: any) { + async update(id: string, documentType: UpdateDocumentTypeRequestModel) { if (!id) throw new Error('Id is missing'); - let body: string; + documentType = {...documentType}; - try { - body = JSON.stringify(document); - } catch (error) { - console.error(error); - return Promise.reject(); - } + // TODO: Hack to remove some props that ruins the document-type post end-point. + (documentType as any).$type = undefined; + (documentType as any).id = undefined; - // TODO: use resources when end point is ready: - return tryExecuteAndNotify( - this.#host, - fetch(`/umbraco/management/api/v1/document-type/${document.id}`, { - method: 'PUT', - body: body, - headers: { - 'Content-Type': 'application/json', - }, - }) as any - ); + return tryExecuteAndNotify(this.#host, DocumentTypeResource.putDocumentTypeById({ id, requestBody: documentType })); } /** @@ -143,16 +143,8 @@ export class UmbDocumentTypeServerDataSource implements UmbDataSource res.json()) - ); + // TODO: Hack the type to avoid type-error here: + return tryExecuteAndNotify(this.#host, DocumentTypeResource.deleteDocumentTypeById({ id })) as any; } /** diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace-editor.element.ts index 8d10ebc83b..502174874d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace-editor.element.ts @@ -8,6 +8,7 @@ import { UMB_ICON_PICKER_MODAL, } from '@umbraco-cms/backoffice/modal'; import { UMB_ENTITY_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace'; +import { generateAlias } from '@umbraco-cms/backoffice/utils'; @customElement('umb-document-type-workspace-editor') export class UmbDocumentTypeWorkspaceEditorElement extends UmbLitElement { @state() @@ -25,6 +26,9 @@ export class UmbDocumentTypeWorkspaceEditorElement extends UmbLitElement { @state() private _alias?: string; + @state() + private _aliasLocked = true; + private _modalContext?: UmbModalManagerContext; constructor() { @@ -42,24 +46,45 @@ export class UmbDocumentTypeWorkspaceEditorElement extends UmbLitElement { #observeDocumentType() { if (!this.#workspaceContext) return; - this.observe(this.#workspaceContext.name, (name) => (this._name = name)); - this.observe(this.#workspaceContext.alias, (alias) => (this._alias = alias)); - this.observe(this.#workspaceContext.icon, (icon) => (this._icon = icon)); + this.observe(this.#workspaceContext.name, (name) => (this._name = name), '_observeName'); + this.observe(this.#workspaceContext.alias, (alias) => (this._alias = alias), '_observeAlias'); + this.observe(this.#workspaceContext.icon, (icon) => (this._icon = icon), '_observeIcon'); + + this.observe(this.#workspaceContext.isNew, (isNew) => { + if(isNew) { + // TODO: Would be good with a more general way to bring focus to the name input. + (this.shadowRoot?.querySelector('#name') as HTMLElement)?.focus(); + } + this.removeControllerByUnique('_observeIsNew'); + }, '_observeIsNew'); + } // TODO. find a way where we don't have to do this for all workspaces. - private _handleNameInput(event: UUIInputEvent) { + #onNameChange(event: UUIInputEvent) { if (event instanceof UUIInputEvent) { const target = event.composedPath()[0] as UUIInputElement; if (typeof target?.value === 'string') { + + const oldName = this._name; + const oldAlias = this._alias; + const newName = event.target.value.toString(); + if (this._aliasLocked) { + const expectedOldAlias = generateAlias(oldName ?? ''); + // Only update the alias if the alias matches a generated alias of the old name (otherwise the alias is considered one written by the user.) + if (expectedOldAlias === oldAlias) { + this.#workspaceContext?.setAlias(generateAlias(newName)); + } + } this.#workspaceContext?.setName(target.value); } } } + // TODO. find a way where we don't have to do this for all workspaces. - private _handleAliasInput(event: UUIInputEvent) { + #onAliasChange(event: UUIInputEvent) { if (event instanceof UUIInputEvent) { const target = event.composedPath()[0] as UUIInputElement; @@ -70,6 +95,10 @@ export class UmbDocumentTypeWorkspaceEditorElement extends UmbLitElement { event.stopPropagation(); } + #onToggleAliasLock() { + this._aliasLocked = !this._aliasLocked; + } + private async _handleIconClick() { const modalContext = this._modalContext?.open(UMB_ICON_PICKER_MODAL, { icon: this._icon, @@ -90,10 +119,23 @@ export class UmbDocumentTypeWorkspaceEditorElement extends UmbLitElement { - - + + + + +
''} id="alias-lock" slot="prepend"> + +
+
+ +
@@ -133,10 +175,14 @@ export class UmbDocumentTypeWorkspaceEditorElement extends UmbLitElement { align-items: center; } - #alias { - height: calc(100% - 2px); - --uui-input-border-width: 0; - --uui-button-height: calc(100% -2px); + #alias-lock { + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + } + #alias-lock uui-icon { + margin-bottom: 2px; } #icon { @@ -144,6 +190,7 @@ export class UmbDocumentTypeWorkspaceEditorElement extends UmbLitElement { margin-right: var(--uui-size-space-2); margin-left: calc(var(--uui-size-space-4) * -1); } + `, ]; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.context.ts index f5120f953f..a3da2de2c1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.context.ts @@ -114,7 +114,8 @@ export class UmbDocumentTypeWorkspaceContext this.structure.updateOwnerDocumentType({ defaultTemplateId }); } - async createScaffold(parentId: string | null) { + async create(parentId: string | null) { + const { data } = await this.structure.createScaffold(parentId); if (!data) return undefined; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.element.ts index 1c19c1fe59..125606706d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type-workspace.element.ts @@ -1,30 +1,46 @@ import { UmbDocumentTypeWorkspaceContext } from './document-type-workspace.context.js'; -import { UmbDocumentTypeWorkspaceEditorElement } from './document-type-workspace-editor.element.js'; import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui'; import { html , customElement, state } from '@umbraco-cms/backoffice/external/lit'; -import type { UmbRoute } from '@umbraco-cms/backoffice/router'; +import { UmbRoute, UmbRouterSlotInitEvent, generateRoutePathBuilder } from '@umbraco-cms/backoffice/router'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; @customElement('umb-document-type-workspace') export class UmbDocumentTypeWorkspaceElement extends UmbLitElement { #workspaceContext = new UmbDocumentTypeWorkspaceContext(this); - #element = new UmbDocumentTypeWorkspaceEditorElement(); + #routerPath? = ''; @state() _routes: UmbRoute[] = [ { path: 'create/:parentId', - component: () => this.#element, + component: import('./document-type-workspace-editor.element.js'), setup: (_component, info) => { const parentId = info.match.params.parentId === 'null' ? null : info.match.params.parentId; - this.#workspaceContext.createScaffold(parentId); + this.#workspaceContext.create(parentId); + + // Navigate to edit route when language is created: + this.observe( + this.#workspaceContext.isNew, + (isNew) => { + if (isNew === false) { + const id = this.#workspaceContext.getEntityId(); + if (this.#routerPath && id) { + const routeBasePath = this.#routerPath.endsWith('/') ? this.#routerPath : this.#routerPath + '/'; + // TODO: Revisit if this is the right way to change URL: + const newPath = generateRoutePathBuilder(routeBasePath + 'edit/:id')({ id }); + window.history.pushState({}, '', newPath); + } + } + }, + '_observeIsNew' + ); }, }, { path: 'edit/:id', - component: () => this.#element, + component: import('./document-type-workspace-editor.element.js'), setup: (_component, info) => { - console.log('Setup for edit/id'); + this.removeControllerByUnique('_observeIsNew'); const id = info.match.params.id; this.#workspaceContext.load(id); }, @@ -32,7 +48,9 @@ export class UmbDocumentTypeWorkspaceElement extends UmbLitElement { ]; render() { - return html` `; + return html` { + this.#routerPath = event.target.absoluteRouterPath; + }}> `; } static styles = [UUITextStyles]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts index 45fcdb1a6c..1ce12fff8c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts @@ -6,7 +6,7 @@ import { UmbSorterController, UmbSorterConfig } from '@umbraco-cms/backoffice/so import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { DocumentTypePropertyTypeResponseModel, - PropertyTypeResponseModelBaseModel, + PropertyTypeModelBaseModel, } from '@umbraco-cms/backoffice/backend-api'; import { UMB_MODAL_MANAGER_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/modal'; import './document-type-workspace-view-edit-property.element.js'; @@ -78,9 +78,7 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle _propertyStructureHelper = new UmbContentTypePropertyStructureHelper(this); @state() - _propertyStructure: Array = []; - - #modalContext?: typeof UMB_MODAL_MANAGER_CONTEXT_TOKEN.TYPE; + _propertyStructure: Array = []; constructor() { super(); @@ -90,7 +88,6 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle (workspaceContext as UmbDocumentTypeWorkspaceContext).structure ); }); - this.consumeContext(UMB_MODAL_MANAGER_CONTEXT_TOKEN, (instance) => (this.#modalContext = instance)); this.observe(this._propertyStructureHelper.propertyStructure, (propertyStructure) => { this._propertyStructure = propertyStructure; this.#propertySorter.setModel(this._propertyStructure); @@ -101,25 +98,16 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle const property = await this._propertyStructureHelper.addProperty(this._containerId); if (!property) return; - // TODO: Figure out how we from this location can get into the routeable modal.. - /* - // Take id and parse to modal: - console.log('property id:', property.id!, property); + // TODO: Figure out how we from this location can get into the route modal, via URL. + // The modal is registered by the document-type-workspace-view-edit-property element, therefor a bit hard to get the URL from here. - // TODO: route modal.. - const modalContext = this.#modalContext?.open(UMB_PROPERTY_SETTINGS_MODAL); - - modalContext?.onSubmit().then((result) => { - console.log(result); - }); - */ } render() { return html`
${repeat( this._propertyStructure, - (property) => property.alias ?? '' + property.containerId ?? '' + (property as any).sortOrder ?? '', + (property) => property.id ?? '' + property.containerId ?? '' + (property as any).sortOrder ?? '', (property) => html` { - if (e.target) this._singleValueUpdate('name', (e.target as HTMLInputElement).value); - }}> - + + { if (e.target) this._singleValueUpdate('alias', (e.target as HTMLInputElement).value); - }}> + }} + > + +
''} id="alias-lock" slot="prepend"> + +
+

= []; + _groups: Array = []; @state() _hasProperties = false; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts index fd1b0b208a..68839a3cd9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit.element.ts @@ -5,7 +5,7 @@ import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui'; import { UmbContentTypeContainerStructureHelper } from '@umbraco-cms/backoffice/content-type'; import { encodeFolderName, UmbRouterSlotChangeEvent, UmbRouterSlotInitEvent } from '@umbraco-cms/backoffice/router'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; -import { PropertyTypeContainerResponseModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; +import { PropertyTypeContainerModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; import { UMB_ENTITY_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace'; import type { UmbRoute } from '@umbraco-cms/backoffice/router'; import { UmbWorkspaceEditorViewExtensionElement } from '@umbraco-cms/backoffice/extension-registry'; @@ -22,7 +22,7 @@ export class UmbDocumentTypeWorkspaceViewEditElement private _routes: UmbRoute[] = []; @state() - _tabs: Array = []; + _tabs: Array = []; @state() private _routerPath?: string; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/document.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/document.repository.ts index 2f4e5a94ad..9ccd7feb2c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/document.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/document.repository.ts @@ -13,10 +13,9 @@ import { } from '@umbraco-cms/backoffice/backend-api'; import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification'; -type ItemType = DocumentResponseModel; - export class UmbDocumentRepository - implements UmbTreeRepository, UmbDetailRepository + implements UmbTreeRepository, + UmbDetailRepository { #init!: Promise; @@ -124,10 +123,10 @@ export class UmbDocumentRepository // DETAILS: - async createScaffold(documentTypeKey: string) { + async createScaffold(documentTypeKey: string, preset?: Partial) { if (!documentTypeKey) throw new Error('Document type id is missing'); await this.#init; - return this.#detailDataSource.createScaffold(documentTypeKey); + return this.#detailDataSource.createScaffold(documentTypeKey, preset); } async requestById(id: string) { @@ -165,14 +164,18 @@ export class UmbDocumentRepository const { error } = await this.#detailDataSource.insert(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 + this.#store?.append(item); + // TODO: Update tree store with the new item? or ask tree to request the new item? + + // TODO: Revisit this call, as we should be able to update tree on client. + await this.requestRootTreeItems(); + const notification = { data: { message: `Document created` } }; this.#notificationContext?.peek('positive', notification); } - // TODO: we currently don't use the detail store for anything. - // Consider to look up the data before fetching from the server - this.#store?.append(item); - // TODO: Update tree store with the new item? or ask tree to request the new item? return { error }; } @@ -193,6 +196,9 @@ export class UmbDocumentRepository //this.#treeStore?.updateItem(item.id, { name: item.name });// Port data to tree store. // TODO: would be nice to align the stores on methods/methodNames. + // TODO: Revisit this call, as we should be able to update tree on client. + await this.requestRootTreeItems(); + const notification = { data: { message: `Document saved` } }; this.#notificationContext?.peek('positive', notification); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/sources/document.server.data.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/sources/document.server.data.ts index d88cf51c01..6cf3c8cb9d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/sources/document.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/sources/document.server.data.ts @@ -55,16 +55,17 @@ export class UmbDocumentServerDataSource * @return {*} * @memberof UmbDocumentServerDataSource */ - async createScaffold(documentTypeId: string) { + async createScaffold(documentTypeId: string, preset?: Partial) { const data: DocumentResponseModel = { urls: [], templateId: null, + parentId: null, id: UmbId.new(), contentTypeId: documentTypeId, values: [], variants: [ { - $type: '', + $type: 'DocumentVariantRequestModel', state: ContentStateModel.DRAFT, publishDate: null, culture: null, @@ -74,6 +75,7 @@ export class UmbDocumentServerDataSource updateDate: undefined, }, ], + ...preset, }; return { data }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/sources/document.tree.server.data.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/sources/document.tree.server.data.ts index adcfa448c2..e9813bad40 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/sources/document.tree.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/repository/sources/document.tree.server.data.ts @@ -68,7 +68,7 @@ export class UmbDocumentTreeServerDataSource implements UmbTreeDataSource { async getChildrenOf(parentId: string | null) { if (parentId === undefined) throw new Error('Parent id is missing'); - /* TODO: should we make getRootItems() internal + /* TODO: should we make getRootItems() internal so it only is a server concern that there are two endpoints? */ if (parentId === null) { return this.getRootItems(); diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts index 473d8746ec..b6ac678d65 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts @@ -75,8 +75,8 @@ export class UmbDocumentWorkspaceContext return data || undefined; } - async createScaffold(documentTypeKey: string) { - const { data } = await this.repository.createScaffold(documentTypeKey); + async create(documentTypeKey: string, parentId: string | null) { + const { data } = await this.repository.createScaffold(documentTypeKey, {parentId}); if (!data) return undefined; this.setIsNew(true); diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.element.ts index 30c3797cd4..c670c1c2ea 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.element.ts @@ -9,24 +9,23 @@ import './document-workspace-editor.element.js'; @customElement('umb-document-workspace') export class UmbDocumentWorkspaceElement extends UmbLitElement { #workspaceContext = new UmbDocumentWorkspaceContext(this); - #element = document.createElement('umb-document-workspace-editor'); @state() _routes: UmbRoute[] = [ { path: 'create/:parentId/:documentTypeKey', - component: () => this.#element, + component: import('./document-workspace-editor.element.js'), setup: async (_component, info) => { // TODO: use parent id: // TODO: Notice the perspective of permissions here, we need to check if the user has access to create a document of this type under this parent? - const parentId = info.match.params.parentId; + const parentId = info.match.params.parentId === 'null' ? null : info.match.params.parentId; const documentTypeKey = info.match.params.documentTypeKey; - this.#workspaceContext.createScaffold(documentTypeKey); + this.#workspaceContext.create(documentTypeKey, parentId); }, }, { path: 'edit/:id', - component: () => this.#element, + component: import('./document-workspace-editor.element.js'), setup: (_component, info) => { const id = info.match.params.id; this.#workspaceContext.load(id); diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit-properties.element.ts index 95d621fb29..6b060f2b5e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit-properties.element.ts @@ -3,7 +3,7 @@ import { css, html , customElement, property, state , repeat } from '@umbraco-cm import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui'; import { UmbContentTypePropertyStructureHelper, PropertyContainerTypes } from '@umbraco-cms/backoffice/content-type'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; -import { PropertyTypeResponseModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; +import { PropertyTypeModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; import { UMB_ENTITY_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace'; @customElement('umb-document-workspace-view-edit-properties') export class UmbDocumentWorkspaceViewEditPropertiesElement extends UmbLitElement { @@ -26,7 +26,7 @@ export class UmbDocumentWorkspaceViewEditPropertiesElement extends UmbLitElement _propertyStructureHelper = new UmbContentTypePropertyStructureHelper(this); @state() - _propertyStructure: Array = []; + _propertyStructure: Array = []; constructor() { super(); diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit-tab.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit-tab.element.ts index da4d776a5f..6d48aa39ec 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit-tab.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit-tab.element.ts @@ -3,7 +3,7 @@ import { css, html, customElement, property, state, repeat } from '@umbraco-cms/ import { UUITextStyles } from '@umbraco-cms/backoffice/external/uui'; import { UmbContentTypeContainerStructureHelper } from '@umbraco-cms/backoffice/content-type'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; -import { PropertyTypeContainerResponseModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; +import { PropertyTypeContainerModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; import { UMB_ENTITY_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace'; import './document-workspace-view-edit-properties.element.js'; @@ -34,7 +34,7 @@ export class UmbDocumentWorkspaceViewEditTabElement extends UmbLitElement { _groupStructureHelper = new UmbContentTypeContainerStructureHelper(this); @state() - _groups: Array = []; + _groups: Array = []; @state() _hasProperties = false; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit.element.ts index 21f1b78863..69b6527bb2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit.element.ts @@ -9,7 +9,7 @@ import { UmbRouterSlotInitEvent, } from '@umbraco-cms/backoffice/router'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; -import { PropertyTypeContainerResponseModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; +import { PropertyTypeContainerModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; import { UMB_ENTITY_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace'; import { UmbWorkspaceEditorViewExtensionElement } from '@umbraco-cms/backoffice/extension-registry'; @@ -25,7 +25,7 @@ export class UmbDocumentWorkspaceViewEditElement private _routes: UmbRoute[] = []; @state() - _tabs: Array = []; + _tabs: Array = []; @state() private _routerPath?: string; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/media-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/media-type-workspace.context.ts index 739b0a6a51..33661d96f1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/media-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/media-type-workspace.context.ts @@ -44,7 +44,7 @@ export class UmbWorkspaceMediaTypeContext } } - async createScaffold() { + async create() { const { data } = await this.repository.createScaffold(); if (!data) return; this.setIsNew(true); diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/media-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/media-workspace.context.ts index 0ee1178950..4af12c43e9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/media-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/workspace/media-workspace.context.ts @@ -53,7 +53,7 @@ export class UmbMediaWorkspaceContext } } - async createScaffold(parentId: string | null) { + async create(parentId: string | null) { const { data } = await this.repository.createScaffold(parentId); if (!data) return; this.setIsNew(true); diff --git a/src/Umbraco.Web.UI.Client/src/packages/members/member-groups/workspace/member-group-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/members/member-groups/workspace/member-group-workspace.context.ts index 5905241285..a694307280 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/members/member-groups/workspace/member-group-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/members/member-groups/workspace/member-group-workspace.context.ts @@ -46,7 +46,7 @@ export class UmbWorkspaceMemberGroupContext } } - async createScaffold() { + async create() { const { data } = await this.repository.createScaffold(); if (!data) return; this.setIsNew(true); diff --git a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/components/data-type-flow-input/data-type-flow-input.element.ts b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/components/data-type-flow-input/data-type-flow-input.element.ts index 4593633482..0562997050 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/components/data-type-flow-input/data-type-flow-input.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/components/data-type-flow-input/data-type-flow-input.element.ts @@ -2,7 +2,7 @@ import type { UmbDataTypeModel } from '../../models.js'; import { css, html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UUITextStyles, FormControlMixin } from '@umbraco-cms/backoffice/external/uui'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; -import { UmbModalRouteRegistrationController, UMB_DATA_TYPE_PICKER_FLOW_MODAL } from '@umbraco-cms/backoffice/modal'; +import { UmbModalRouteRegistrationController, UMB_DATA_TYPE_PICKER_FLOW_MODAL, UMB_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/modal'; import { UmbRepositoryItemsManager } from '@umbraco-cms/backoffice/repository'; // Note: Does only support picking a single data type. But this could be developed later into this same component. To follow other picker input components. @@ -37,8 +37,11 @@ export class UmbInputDataTypeElement extends FormControlMixin(UmbLitElement) { this.#itemsManager.setUniques(super.value.split(',')); } + #editDataTypeModal?: UmbModalRouteRegistrationController; + @state() - private _modalRoute?: string; + private _createRoute?: string; + constructor() { super(); @@ -51,6 +54,12 @@ export class UmbInputDataTypeElement extends FormControlMixin(UmbLitElement) { this._items = items; }); + + this.#editDataTypeModal = new UmbModalRouteRegistrationController(this, UMB_WORKSPACE_MODAL) + .onSetup(() => { + return { entityType: 'data-type', preset: {} }; + }) + new UmbModalRouteRegistrationController(this, UMB_DATA_TYPE_PICKER_FLOW_MODAL) .onSetup(() => { return { @@ -64,8 +73,7 @@ export class UmbInputDataTypeElement extends FormControlMixin(UmbLitElement) { this.dispatchEvent(new CustomEvent('change', { composed: true, bubbles: true })); }) .observeRouteBuilder((routeBuilder) => { - this._modalRoute = routeBuilder(null); - this.requestUpdate('_modalRoute'); + this._createRoute = routeBuilder(null); }); } @@ -77,13 +85,14 @@ export class UmbInputDataTypeElement extends FormControlMixin(UmbLitElement) { property-editor-ui-alias=${this._items[0].propertyEditorAlias} property-editor-model-alias=${this._items[0].propertyEditorUiAlias} @open=${() => { - console.warn('TO BE DONE..'); + // TODO: Could use something smarter for workspace modals, as I would like to avoid setting the rest of the URL here: + this.#editDataTypeModal?.open({}, 'edit/' + this._items![0].id) }} border> - + ` @@ -93,7 +102,7 @@ export class UmbInputDataTypeElement extends FormControlMixin(UmbLitElement) { label="Select Property Editor" look="placeholder" color="default" - .href=${this._modalRoute}> + .href=${this._createRoute}> `; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/modals/data-type-picker-flow/data-type-picker-flow-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/modals/data-type-picker-flow/data-type-picker-flow-modal.element.ts index 921973d43d..eeb1e2089d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/modals/data-type-picker-flow/data-type-picker-flow-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/modals/data-type-picker-flow/data-type-picker-flow-modal.element.ts @@ -57,8 +57,6 @@ export class UmbDataTypePickerFlowModalElement extends UmbLitElement { #propertyEditorUIs: Array = []; #currentFilterQuery = ''; - //UMB_DATA_TYPE_PICKER_FLOW_UI_PICKER_MODAL; - constructor() { super(); this.#repository = new UmbDataTypeRepository(this); @@ -73,6 +71,7 @@ export class UmbDataTypePickerFlowModalElement extends UmbLitElement { .onSubmit((submitData) => { if (submitData.dataTypeId) { this._select(submitData.dataTypeId); + this._submit(); } else if (submitData.createNewWithPropertyEditorUiAlias) { this._createDataType(submitData.createNewWithPropertyEditorUiAlias); } @@ -88,7 +87,9 @@ export class UmbDataTypePickerFlowModalElement extends UmbLitElement { return { entityType: 'data-type', preset: { propertyEditorUiAlias: params.uiAlias } }; }) .onSubmit((submitData) => { - console.log('submitData', submitData); + this._select(submitData.id); + this._submit(); + }); this.#init(); @@ -120,6 +121,7 @@ export class UmbDataTypePickerFlowModalElement extends UmbLitElement { private _handleDataTypeClick(dataType: EntityTreeItemResponseModel) { if (dataType.id) { this._select(dataType.id); + this._submit(); } } @@ -170,7 +172,6 @@ export class UmbDataTypePickerFlowModalElement extends UmbLitElement { ${this._renderFilter()} ${this._renderGrid()}

-
`; diff --git a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/repository/data-type.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/repository/data-type.repository.ts index 959ba64508..51eb0d84a6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/repository/data-type.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/repository/data-type.repository.ts @@ -227,7 +227,9 @@ export class UmbDataTypeRepository // Consider notify a workspace if a template is updated in the store while someone is editing it. // TODO: would be nice to align the stores on methods/methodNames. // this.#detailStore?.append(dataType); + // TODO: This is parsing on the full models to the tree and item store. Those should only contain the data they need. I don't know, at this point, if thats a repository or store responsibility. this.#treeStore?.updateItem(id, updatedDataType); + this.#itemStore?.updateItem(id, updatedDataType); const notification = { data: { message: `Data Type saved` } }; this.#notificationContext?.peek('positive', notification); @@ -249,6 +251,7 @@ export class UmbDataTypeRepository // TODO: would be nice to align the stores on methods/methodNames. this.#detailStore?.remove([id]); this.#treeStore?.removeItem(id); + this.#itemStore?.removeItem(id); const notification = { data: { message: `Data Type deleted` } }; this.#notificationContext?.peek('positive', notification); diff --git a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.context.ts index dc0e25b629..074f6f8cb6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.context.ts @@ -27,7 +27,7 @@ export class UmbDataTypeWorkspaceContext } } - async createScaffold(parentId: string | null) { + async create(parentId: string | null) { let { data } = await this.repository.createScaffold(parentId); if (this.modalContext) { data = { ...data, ...this.modalContext.data.preset }; @@ -78,7 +78,7 @@ export class UmbDataTypeWorkspaceContext if (!this.#data.value) return; if (!this.#data.value.id) return; - if (this.isNew) { + if (this.getIsNew()) { await this.repository.create(this.#data.value); } else { await this.repository.save(this.#data.value.id, this.#data.value); diff --git a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.element.ts index 2bda82db04..97c056ac9e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/data-type-workspace.element.ts @@ -18,7 +18,7 @@ export class UmbDataTypeWorkspaceElement extends UmbLitElement { component: () => this.#element, setup: (_component, info) => { const parentId = info.match.params.parentId === 'null' ? null : info.match.params.parentId; - this.#workspaceContext.createScaffold(parentId); + this.#workspaceContext.create(parentId); }, }, { diff --git a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/manifests.ts index a1d3852160..6732de2659 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/settings/data-types/workspace/manifests.ts @@ -1,6 +1,5 @@ import { UmbSaveWorkspaceAction } from '@umbraco-cms/backoffice/workspace'; import type { - ManifestModal, ManifestWorkspace, ManifestWorkspaceAction, ManifestWorkspaceEditorView, diff --git a/src/Umbraco.Web.UI.Client/src/packages/settings/languages/workspace/language/language-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/settings/languages/workspace/language/language-workspace.context.ts index f5c2169f92..d45a6e24d1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/settings/languages/workspace/language/language-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/settings/languages/workspace/language/language-workspace.context.ts @@ -27,7 +27,7 @@ export class UmbLanguageWorkspaceContext } } - async createScaffold() { + async create() { const { data } = await this.repository.createScaffold(); if (!data) return; this.setIsNew(true); diff --git a/src/Umbraco.Web.UI.Client/src/packages/settings/languages/workspace/language/language-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/settings/languages/workspace/language/language-workspace.element.ts index a5fb89a4d1..024ff5b6a6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/settings/languages/workspace/language/language-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/settings/languages/workspace/language/language-workspace.element.ts @@ -40,7 +40,7 @@ export class UmbLanguageWorkspaceElement extends UmbLitElement { path: 'create', component: this.#getComponentElement, setup: async () => { - this.#languageWorkspaceContext.createScaffold(); + this.#languageWorkspaceContext.create(); // Navigate to edit route when language is created: this.observe( diff --git a/src/Umbraco.Web.UI.Client/src/packages/tags/repository/tag.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/tags/repository/tag.repository.ts index 9c72e60885..49a4ea74b9 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/tags/repository/tag.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/tags/repository/tag.repository.ts @@ -42,7 +42,7 @@ export class UmbTagRepository { if (data) { // TODO: allow to append an array of items to the store - // TODO: append culture? "Invariant" if null. + // TODO: Lone: append culture? "Invariant" if null. Niels: Actually, as of my current stand point, I think we should aim for invariant to be the value of ´null´. data.items.forEach((x) => this.#tagStore?.append(x)); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/repository/partial-views.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/repository/partial-views.repository.ts index 50914ad489..5c0dddd0b0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/repository/partial-views.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/repository/partial-views.repository.ts @@ -1,10 +1,8 @@ import { UmbPartialViewDetailServerDataSource } from './sources/partial-views.detail.server.data.js'; import { UmbPartialViewsTreeServerDataSource } from './sources/partial-views.tree.server.data.js'; -import { UmbPartialViewsStore, UMB_PARTIAL_VIEWS_STORE_CONTEXT_TOKEN } from './partial-views.store.js'; import { UmbPartialViewsTreeStore, UMB_PARTIAL_VIEW_TREE_STORE_CONTEXT_TOKEN } from './partial-views.tree.store.js'; import { Observable } from '@umbraco-cms/backoffice/external/rxjs'; import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; -import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; import { ProblemDetailsModel } from '@umbraco-cms/backoffice/backend-api'; import { UmbDetailRepository, UmbTreeRepository } from '@umbraco-cms/backoffice/repository'; @@ -18,9 +16,6 @@ export class UmbTemplateRepository implements UmbTreeRepository, UmbDetailR #detailDataSource: UmbPartialViewDetailServerDataSource; #treeStore?: UmbPartialViewsTreeStore; - #store?: UmbPartialViewsStore; - - #notificationContext?: UmbNotificationContext; constructor(host: UmbControllerHostElement) { this.#host = host; @@ -32,19 +27,12 @@ export class UmbTemplateRepository implements UmbTreeRepository, UmbDetailR new UmbContextConsumerController(this.#host, UMB_PARTIAL_VIEW_TREE_STORE_CONTEXT_TOKEN, (instance) => { this.#treeStore = instance; }), - - new UmbContextConsumerController(this.#host, UMB_PARTIAL_VIEWS_STORE_CONTEXT_TOKEN, (instance) => { - this.#store = instance; - }), - - new UmbContextConsumerController(this.#host, UMB_NOTIFICATION_CONTEXT_TOKEN, (instance) => { - this.#notificationContext = instance; - }), ]); } requestTreeRoot(): Promise<{ data?: UmbTreeRootEntityModel | undefined; error?: ProblemDetailsModel | undefined }> { - throw new Error('Method not implemented.'); + //throw new Error('Method not implemented.'); + return {data: undefined, error: undefined} as any; } requestItemsLegacy?: @@ -61,6 +49,9 @@ export class UmbTemplateRepository implements UmbTreeRepository, UmbDetailR throw new Error('Method not implemented.'); } + // TODO: This method to be done, or able to go away? + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore requestById(id: string): Promise<{ data?: any; error?: ProblemDetailsModel | undefined }> { throw new Error('Method not implemented.'); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/workspace/partial-views-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/workspace/partial-views-workspace.context.ts index 6372e0581a..6ccc43c323 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/workspace/partial-views-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/partial-views/workspace/partial-views-workspace.context.ts @@ -46,7 +46,7 @@ export class UmbPartialViewsWorkspaceContext extends UmbWorkspaceContext this.#element, setup: async (component: PageComponent, info: IRoutingInfo) => { const parentKey = info.match.params.parentKey; - this.#partialViewsWorkspaceContext.createScaffold(parentKey); + this.#partialViewsWorkspaceContext.create(parentKey); }, }, { diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/workspace/template-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/workspace/template-workspace.context.ts index f8fb761ba1..7dc7df9b88 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/workspace/template-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/workspace/template-workspace.context.ts @@ -128,7 +128,7 @@ export class UmbTemplateWorkspaceContext extends UmbWorkspaceContext this.#element, setup: (component: PageComponent, info: IRoutingInfo) => { const parentKey = info.match.params.parentKey; - this.#templateWorkspaceContext.createScaffold(parentKey); + this.#templateWorkspaceContext.create(parentKey); }, }, { diff --git a/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/entity-actions/create/create.action.ts b/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/entity-actions/create/create.action.ts index 274a082428..efec29dff0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/entity-actions/create/create.action.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/entity-actions/create/create.action.ts @@ -48,7 +48,7 @@ export default class UmbCreateDictionaryEntityAction extends UmbEntityActionBase const { name } = await modalContext.onSubmit(); if (!name) return; - const { data } = await this.repository.createScaffold(this.unique, name); + const { data } = await this.repository.createScaffold(this.unique, {name}); // TODO => get location header to route to new item console.log(data); diff --git a/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/repository/dictionary.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/repository/dictionary.repository.ts index 3e1d941674..892ef11790 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/repository/dictionary.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/repository/dictionary.repository.ts @@ -127,10 +127,11 @@ export class UmbDictionaryRepository // DETAILS - async createScaffold(parentId: string | null, name?: string) { + // TODO: consider if we want to create a specific createScaffoldWithName, to loose the coupling to the model. + async createScaffold(parentId: string | null, preset?: Partial) { if (parentId === undefined) throw new Error('Parent id is missing'); await this.#init; - return this.#detailSource.createScaffold(parentId, name); + return this.#detailSource.createScaffold(parentId, preset); } async requestById(id: string) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/repository/sources/dictionary.detail.server.data.ts b/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/repository/sources/dictionary.detail.server.data.ts index 3db986cde2..018d06813a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/repository/sources/dictionary.detail.server.data.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/repository/sources/dictionary.detail.server.data.ts @@ -33,12 +33,13 @@ export class UmbDictionaryDetailServerDataSource * @return {*} * @memberof UmbDictionaryDetailServerDataSource */ - async createScaffold(parentId?: string | null, name?: string) { + async createScaffold(parentId?: string | null, preset?: Partial) { const data = { id: UmbId.new(), parentId, - name, + name: '', translations: [], + ...preset }; return { data }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/workspace/dictionary-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/workspace/dictionary-workspace.context.ts index db2c269e2e..1bdddb14da 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/workspace/dictionary-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/translation/dictionary/workspace/dictionary-workspace.context.ts @@ -62,7 +62,7 @@ export class UmbDictionaryWorkspaceContext } } - async createScaffold(parentId: string | null) { + async create(parentId: string | null) { const { data } = await this.repository.createScaffold(parentId); if (!data) return; this.setIsNew(true); diff --git a/src/Umbraco.Web.UI.Client/src/packages/users/user-groups/repository/user-group.repository.ts b/src/Umbraco.Web.UI.Client/src/packages/users/user-groups/repository/user-group.repository.ts index 758ec296a4..6f4e013de3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/users/user-groups/repository/user-group.repository.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/users/user-groups/repository/user-group.repository.ts @@ -18,8 +18,8 @@ import { UmbDetailRepository, UmbItemDataSource, UmbItemRepository, - UmbRepositoryErrorResponse, - UmbRepositoryResponse, + UmbDataSourceErrorResponse, + DataSourceResponse, } from '@umbraco-cms/backoffice/repository'; import { UmbContextConsumerController } from '@umbraco-cms/backoffice/context-api'; import { UMB_NOTIFICATION_CONTEXT_TOKEN, UmbNotificationContext } from '@umbraco-cms/backoffice/notification'; @@ -69,7 +69,7 @@ export class UmbUserGroupRepository }).asPromise(), ]); } - createScaffold(parentId: string | null): Promise> { + createScaffold(parentId: string | null): Promise> { return this.#detailSource.createScaffold(parentId); } @@ -113,7 +113,7 @@ export class UmbUserGroupRepository throw new Error('Method not implemented.'); } - async create(userGroupRequestData: any): Promise> { + async create(userGroupRequestData: any): Promise> { if (!userGroupRequestData) throw new Error('Data is missing'); const { data, error } = await this.#detailSource.insert(userGroupRequestData); @@ -144,7 +144,7 @@ export class UmbUserGroupRepository return { data, error }; } - async delete(id: string): Promise { + async delete(id: string): Promise { if (!id) throw new Error('UserGroup id is missing'); const { error } = await this.#detailSource.delete(id); diff --git a/src/Umbraco.Web.UI.Client/src/packages/users/user-groups/workspace/user-group-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/users/user-groups/workspace/user-group-workspace.context.ts index cf72e7e863..1ae25cde65 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/users/user-groups/workspace/user-group-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/users/user-groups/workspace/user-group-workspace.context.ts @@ -23,7 +23,7 @@ export class UmbUserGroupWorkspaceContext this.#userRepository = new UmbUserRepository(host); } - async createScaffold() { + async create() { const { data } = await this.repository.createScaffold(null); this.setIsNew(true); // TODO: Should the data be the base model or the presentation model? diff --git a/src/Umbraco.Web.UI.Client/src/packages/users/user-groups/workspace/user-group-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/users/user-groups/workspace/user-group-workspace.element.ts index 99df04ce34..0de7deb0f6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/users/user-groups/workspace/user-group-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/users/user-groups/workspace/user-group-workspace.element.ts @@ -16,7 +16,7 @@ export class UmbUserGroupWorkspaceElement extends UmbLitElement { path: 'create', component: () => this.#element, setup: (component, info) => { - this.#workspaceContext.createScaffold(); + this.#workspaceContext.create(); }, }, { diff --git a/src/Umbraco.Web.UI.Client/src/shared/repository/copy-repository.interface.ts b/src/Umbraco.Web.UI.Client/src/shared/repository/copy-repository.interface.ts index a59608100d..93af5f5bf2 100644 --- a/src/Umbraco.Web.UI.Client/src/shared/repository/copy-repository.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/shared/repository/copy-repository.interface.ts @@ -1,5 +1,5 @@ -import { UmbRepositoryResponse } from './detail-repository.interface.js'; +import type { DataSourceResponse } from "./data-source/index.js"; export interface UmbCopyRepository { - copy(unique: string, targetUnique: string): Promise>; + copy(unique: string, targetUnique: string): Promise>; } diff --git a/src/Umbraco.Web.UI.Client/src/shared/repository/detail-repository.interface.ts b/src/Umbraco.Web.UI.Client/src/shared/repository/detail-repository.interface.ts index 4a6319e296..c239e34776 100644 --- a/src/Umbraco.Web.UI.Client/src/shared/repository/detail-repository.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/shared/repository/detail-repository.interface.ts @@ -1,12 +1,6 @@ +import type { DataSourceResponse, UmbDataSourceErrorResponse } from './data-source/index.js'; import { Observable } from '@umbraco-cms/backoffice/external/rxjs'; -import type { ProblemDetailsModel } from '@umbraco-cms/backoffice/backend-api'; -export interface UmbRepositoryErrorResponse { - error?: ProblemDetailsModel; -} -export interface UmbRepositoryResponse extends UmbRepositoryErrorResponse { - data?: T; -} export interface UmbDetailRepository< CreateRequestType = any, @@ -14,10 +8,10 @@ export interface UmbDetailRepository< UpdateRequestType = any, ResponseType = any > { - createScaffold(parentId: string | null): Promise>; - requestById(id: string): Promise>; + createScaffold(parentId: string | null, preset?: Partial): Promise>; + requestById(id: string): Promise>; byId(id: string): Promise>; - create(data: CreateRequestType): Promise>; - save(id: string, data: UpdateRequestType): Promise; - delete(id: string): Promise; + create(data: CreateRequestType): Promise>; + save(id: string, data: UpdateRequestType): Promise; + delete(id: string): Promise; } diff --git a/src/Umbraco.Web.UI.Client/src/shared/repository/move-repository.interface.ts b/src/Umbraco.Web.UI.Client/src/shared/repository/move-repository.interface.ts index 32097d5c34..0493e01ca8 100644 --- a/src/Umbraco.Web.UI.Client/src/shared/repository/move-repository.interface.ts +++ b/src/Umbraco.Web.UI.Client/src/shared/repository/move-repository.interface.ts @@ -1,5 +1,5 @@ -import { UmbRepositoryErrorResponse } from './detail-repository.interface.js'; +import { UmbDataSourceErrorResponse } from "./data-source/index.js"; export interface UmbMoveRepository { - move(unique: string, targetUnique: string): Promise; + move(unique: string, targetUnique: string): Promise; } diff --git a/src/Umbraco.Web.UI.Client/src/shared/router/generate-route-path-builder.function.ts b/src/Umbraco.Web.UI.Client/src/shared/router/generate-route-path-builder.function.ts index 5ad4606f83..f3338f9b1c 100644 --- a/src/Umbraco.Web.UI.Client/src/shared/router/generate-route-path-builder.function.ts +++ b/src/Umbraco.Web.UI.Client/src/shared/router/generate-route-path-builder.function.ts @@ -4,12 +4,12 @@ import { stripSlash } from '@umbraco-cms/backoffice/external/router-slot'; // Th const PARAM_IDENTIFIER = /:([^\\/]+)/g; export function generateRoutePathBuilder(path: string) { - return (params: { [key: string]: string | number } | null) => - params - ? stripSlash( + return (params: { [key: string]: string | number } | null) => { + return '/' + stripSlash( + params ? path.replace(PARAM_IDENTIFIER, (substring: string, ...args: string[]) => { return params[args[0]].toString(); - }) - ) - : path; + } + ): path) + '/'; + } } diff --git a/src/Umbraco.Web.UI.Client/src/shared/router/route.context.ts b/src/Umbraco.Web.UI.Client/src/shared/router/route.context.ts index 30c46ceaaa..ee7543e19b 100644 --- a/src/Umbraco.Web.UI.Client/src/shared/router/route.context.ts +++ b/src/Umbraco.Web.UI.Client/src/shared/router/route.context.ts @@ -11,12 +11,14 @@ import { UMB_MODAL_MANAGER_CONTEXT_TOKEN, UmbModalRouteRegistration } from '@umb const EmptyDiv = document.createElement('div'); +type UmbRoutePlusModalKey = UmbRoute & { __modalKey: string }; + export class UmbRouteContext { #mainRouter: IRouterSlot; #modalRouter: IRouterSlot; #modalRegistrations: UmbModalRouteRegistration[] = []; #modalContext?: typeof UMB_MODAL_MANAGER_CONTEXT_TOKEN.TYPE; - #contextRoutes: UmbRoute[] = []; + #modalRoutes: UmbRoutePlusModalKey[] = []; #routerBasePath?: string; #routerActiveLocalPath?: string; #activeModalPath?: string; @@ -27,14 +29,14 @@ export class UmbRouteContext { new UmbContextProviderController(host, UMB_ROUTE_CONTEXT_TOKEN, this); new UmbContextConsumerController(host, UMB_MODAL_MANAGER_CONTEXT_TOKEN, (context) => { this.#modalContext = context; - this.#generateContextRoutes(); + this.#generateModalRoutes(); }); } public registerModal(registration: UmbModalRouteRegistration) { this.#modalRegistrations.push(registration); this.#generateNewUrlBuilder(registration); - this.#generateContextRoutes(); + this.#generateModalRoutes(); return registration; } @@ -42,11 +44,12 @@ export class UmbRouteContext { const index = this.#modalRegistrations.indexOf(registrationToken); if (index === -1) return; this.#modalRegistrations.splice(index, 1); - this.#generateContextRoutes(); + this.#generateModalRoutes(); } - #generateRoute(modalRegistration: UmbModalRouteRegistration): UmbRoute { + #generateRoute(modalRegistration: UmbModalRouteRegistration): UmbRoutePlusModalKey { return { + __modalKey: modalRegistration.key, path: '/' + modalRegistration.generateModalPath(), component: EmptyDiv, setup: (component, info) => { @@ -72,19 +75,26 @@ export class UmbRouteContext { } } - #generateContextRoutes() { - this.#contextRoutes = this.#modalRegistrations.map((modalRegistration) => { + #generateModalRoutes() { + + const newModals = this.#modalRegistrations.filter(x => !this.#modalRoutes.find(route => x.key === route.__modalKey)); + const routesToRemove = this.#modalRoutes.filter(route => !this.#modalRegistrations.find(x => x.key === route.__modalKey)); + + const cleanedRoutes = this.#modalRoutes.filter(route => !routesToRemove.includes(route)); + + this.#modalRoutes = [...cleanedRoutes, ...newModals.map((modalRegistration) => { return this.#generateRoute(modalRegistration); - }); + })]; // Add an empty route, so there is a route for the router to react on when no modals are open. - this.#contextRoutes.push({ + this.#modalRoutes.push({ + __modalKey: '_empty_', path: '', component: EmptyDiv, }); // TODO: Should we await one frame, to ensure we don't call back too much?. - this.#modalRouter.routes = this.#contextRoutes; + this.#modalRouter.routes = this.#modalRoutes; this.#modalRouter.render(); }