Merge branch 'main' into feature/debug-component

This commit is contained in:
Warren Buckley
2023-02-15 09:14:12 +00:00
committed by GitHub
21 changed files with 713 additions and 159 deletions

View File

@@ -17,8 +17,8 @@ import {
} from './shared/components/backoffice-frame/backoffice.context';
import { UmbDocumentTypeStore } from './documents/document-types/repository/document-type.store';
import { UmbDocumentTypeTreeStore } from './documents/document-types/repository/document-type.tree.store';
import { UmbMediaTypeDetailStore } from './media/media-types/media-type.detail.store';
import { UmbMediaTypeTreeStore } from './media/media-types/media-type.tree.store';
import { UmbMediaTypeDetailStore } from './media/media-types/repository/media-type.detail.store';
import { UmbMediaTypeTreeStore } from './media/media-types/repository/media-type.tree.store';
import { UmbDocumentStore } from './documents/documents/repository/document.store';
import { UmbDocumentTreeStore } from './documents/documents/repository/document.tree.store';
import { UmbMediaDetailStore } from './media/media/repository/media.detail.store';

View File

@@ -0,0 +1,14 @@
import { UmbMediaTypeRepository } from '../repository/media-type.repository';
import { UmbEntityActionBase } from '../../../shared/entity-actions';
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
export class UmbCreateMediaTypeEntityAction extends UmbEntityActionBase<UmbMediaTypeRepository> {
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
}
async execute() {
console.log(`execute for: ${this.unique}`);
alert('open create dialog');
}
}

View File

@@ -0,0 +1,80 @@
import { UmbDeleteEntityAction } from '../../../../backoffice/shared/entity-actions/delete/delete.action';
import { UmbMoveEntityAction } from '../../../../backoffice/shared/entity-actions/move/move.action';
import { MEDIA_TYPE_REPOSITORY_ALIAS } from '../repository/manifests';
import { UmbCopyEntityAction } from '../../../../backoffice/shared/entity-actions/copy/copy.action';
import { UmbCreateMediaTypeEntityAction } from './create.action';
import UmbReloadMediaTypeEntityAction from './reload.action';
import type { ManifestEntityAction } from '@umbraco-cms/models';
const entityType = 'media-type';
const repositoryAlias = MEDIA_TYPE_REPOSITORY_ALIAS;
const entityActions: Array<ManifestEntityAction> = [
{
type: 'entityAction',
alias: 'Umb.EntityAction.MediaType.Create',
name: 'Create Media Type Entity Action',
weight: 500,
meta: {
entityType,
icon: 'umb:add',
label: 'Create',
repositoryAlias,
api: UmbCreateMediaTypeEntityAction,
},
},
{
type: 'entityAction',
alias: 'Umb.EntityAction.MediaType.Move',
name: 'Move Media Type Entity Action',
weight: 400,
meta: {
entityType,
icon: 'umb:enter',
label: 'Move',
repositoryAlias,
api: UmbMoveEntityAction,
},
},
{
type: 'entityAction',
alias: 'Umb.EntityAction.MediaType.Copy',
name: 'Copy Media Type Entity Action',
weight: 300,
meta: {
entityType,
icon: 'umb:documents',
label: 'Copy',
repositoryAlias,
api: UmbCopyEntityAction,
},
},
{
type: 'entityAction',
alias: 'Umb.EntityAction.MediaType.Delete',
name: 'Delete Media Type Entity Action',
weight: 200,
meta: {
entityType,
icon: 'umb:trash',
label: 'Delete',
repositoryAlias,
api: UmbDeleteEntityAction,
},
},
{
type: 'entityAction',
alias: 'Umb.EntityAction.MediaType.Reload',
name: 'Reload Media Type Entity Action',
weight: 100,
meta: {
entityType,
icon: 'umb:refresh',
label: 'Reload',
repositoryAlias,
api: UmbReloadMediaTypeEntityAction,
},
},
];
export const manifests = [...entityActions];

View File

@@ -0,0 +1,16 @@
import { UUITextStyles } from '@umbraco-ui/uui-css';
import { UmbEntityActionBase } from '../../../shared/entity-actions';
import { UmbMediaTypeRepository } from '../repository/media-type.repository';
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
export default class UmbReloadMediaTypeEntityAction extends UmbEntityActionBase<UmbMediaTypeRepository> {
static styles = [UUITextStyles];
constructor(host: UmbControllerHostInterface, repositoryAlias: string, unique: string) {
super(host, repositoryAlias, unique);
}
async execute() {
alert('refresh')
}
}

View File

@@ -1,5 +1,13 @@
import { manifests as sidebarMenuItemManifests } from './sidebar-menu-item/manifests';
import { manifests as treeManifests } from './tree/manifests';
import { manifests as workspaceManifests } from './workspace/manifests';
import { manifests as repositoryManifests } from './repository/manifests';
import { manifests as entityActionManifests } from './entity-actions/manifests';
export const manifests = [...sidebarMenuItemManifests, ...treeManifests, ...workspaceManifests];
export const manifests = [
...sidebarMenuItemManifests,
...treeManifests,
...repositoryManifests,
...workspaceManifests,
...entityActionManifests,
];

View File

@@ -1,60 +0,0 @@
import type { MediaTypeDetails } from '@umbraco-cms/models';
import { UmbContextToken } from '@umbraco-cms/context-api';
import { ArrayState } from '@umbraco-cms/observable-api';
import { UmbEntityDetailStore, UmbStoreBase } from '@umbraco-cms/store';
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
export const UMB_MEDIA_TYPE_DETAIL_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbMediaTypeDetailStore>(
'UmbMediaTypeDetailStore'
);
/**
* @export
* @class UmbMediaTypeDetailStore
* @extends {UmbStoreBase}
* @description - Details Data Store for Media Types
*/
export class UmbMediaTypeDetailStore extends UmbStoreBase implements UmbEntityDetailStore<MediaTypeDetails> {
private _data = new ArrayState<MediaTypeDetails>([], (x) => x.key);
constructor(host: UmbControllerHostInterface) {
super(host, UMB_MEDIA_TYPE_DETAIL_STORE_CONTEXT_TOKEN.toString());
}
getScaffold(entityType: string, parentKey: string | null) {
return {} as MediaTypeDetails;
}
/**
* @description - Request a Data Type by key. The Data Type is added to the store and is returned as an Observable.
* @param {string} key
* @return {*} {(Observable<DataTypeModel | undefined>)}
* @memberof UmbMediaTypesStore
*/
getByKey(key: string) {
return null as any;
}
// TODO: make sure UI somehow can follow the status of this action.
/**
* @description - Save a Media Type.
* @param {Array<MediaTypeDetails>} mediaTypes
* @memberof UmbMediaTypesStore
* @return {*} {Promise<void>}
*/
save(data: MediaTypeDetails[]) {
return null as any;
}
// TODO: How can we avoid having this in both stores?
/**
* @description - Delete a Media Type.
* @param {string[]} keys
* @memberof UmbMediaTypesStore
* @return {*} {Promise<void>}
*/
async delete(keys: string[]) {
// TODO: use backend cli when available.
this._data.remove(keys);
}
}

View File

@@ -1,67 +0,0 @@
import { FolderTreeItemModel, MediaTypeResource } from '@umbraco-cms/backend-api';
import { tryExecuteAndNotify } from '@umbraco-cms/resources';
import { UmbContextToken } from '@umbraco-cms/context-api';
import { ArrayState } from '@umbraco-cms/observable-api';
import { UmbStoreBase } from '@umbraco-cms/store';
import type { UmbControllerHostInterface } from '@umbraco-cms/controller';
export const UMB_DATA_TYPE_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbMediaTypeTreeStore>(
'UmbMediaTypeTreeStore'
);
/**
* @export
* @class UmbMediaTypeTreeStore
* @extends {UmbStoreBase}
* @description - Tree Data Store for Media Types
*/
export class UmbMediaTypeTreeStore extends UmbStoreBase {
#data = new ArrayState<FolderTreeItemModel>([], (x) => x.key);
constructor(host: UmbControllerHostInterface) {
super(host, UMB_DATA_TYPE_TREE_STORE_CONTEXT_TOKEN.toString());
}
getTreeRoot() {
tryExecuteAndNotify(this._host, MediaTypeResource.getTreeMediaTypeRoot({})).then(({ data }) => {
if (data) {
this.#data.append(data.items);
}
});
return this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === null));
}
getTreeItemChildren(key: string) {
tryExecuteAndNotify(
this._host,
MediaTypeResource.getTreeMediaTypeChildren({
parentKey: key,
})
).then(({ data }) => {
if (data) {
this.#data.append(data.items);
}
});
return this.#data.getObservablePart((items) => items.filter((item) => item.parentKey === key));
}
getTreeItems(keys: Array<string>) {
if (keys?.length > 0) {
tryExecuteAndNotify(
this._host,
MediaTypeResource.getTreeMediaTypeItem({
key: keys,
})
).then(({ data }) => {
if (data) {
// TODO: how do we handle if an item has been removed during this session(like in another tab or by another user)?
this.#data.append(data);
}
});
}
return this.#data.getObservablePart((items) => items.filter((item) => keys.includes(item.key ?? '')));
}
}

View File

@@ -0,0 +1,13 @@
import { UmbMediaTypeRepository } from './media-type.repository';
import { ManifestRepository } from 'libs/extensions-registry/repository.models';
export const MEDIA_TYPE_REPOSITORY_ALIAS = 'Umb.Repository.MediaTypes';
const repository: ManifestRepository = {
type: 'repository',
alias: MEDIA_TYPE_REPOSITORY_ALIAS,
name: 'Media Types Repository',
class: UmbMediaTypeRepository,
};
export const manifests = [repository];

View File

@@ -0,0 +1,33 @@
import { UmbContextToken } from '@umbraco-cms/context-api';
import { UmbStoreBase } from '@umbraco-cms/store';
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
import { ArrayState } from '@umbraco-cms/observable-api';
import type { MediaTypeDetails } from '@umbraco-cms/models';
/**
* @export
* @class UmbMediaTypeDetailStore
* @extends {UmbStoreBase}
* @description - Details Data Store for Media Types
*/
export class UmbMediaTypeDetailStore
extends UmbStoreBase
{
#data = new ArrayState<MediaTypeDetails>([], (x) => x.key);
constructor(host: UmbControllerHostInterface) {
super(host, UmbMediaTypeDetailStore.name);
}
append(mediaType: MediaTypeDetails) {
this.#data.append([mediaType]);
}
remove(uniques: string[]) {
this.#data.remove(uniques);
}
}
export const UMB_MEDIA_TYPE_DETAIL_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbMediaTypeDetailStore>(
UmbMediaTypeDetailStore.name
);

View File

@@ -0,0 +1,185 @@
import { UmbMediaTypeTreeStore, UMB_MEDIA_TYPE_TREE_STORE_CONTEXT_TOKEN } from "./media-type.tree.store";
import { UmbMediaTypeDetailServerDataSource } from "./sources/media-type.detail.server.data";
import { UmbMediaTypeDetailStore, UMB_MEDIA_TYPE_DETAIL_STORE_CONTEXT_TOKEN } from "./media-type.detail.store";
import { MediaTypeTreeServerDataSource } from "./sources/media-type.tree.server.data";
import { ProblemDetailsModel } from "@umbraco-cms/backend-api";
import { UmbContextConsumerController } from "@umbraco-cms/context-api";
import { UmbControllerHostInterface } from "@umbraco-cms/controller";
import type { MediaTypeDetails } from "@umbraco-cms/models";
import { UmbNotificationService, UMB_NOTIFICATION_SERVICE_CONTEXT_TOKEN } from "@umbraco-cms/notification";
import { UmbTreeRepository, RepositoryTreeDataSource } from "@umbraco-cms/repository";
export class UmbMediaTypeRepository implements UmbTreeRepository {
#init!: Promise<unknown>;
#host: UmbControllerHostInterface;
#treeSource: RepositoryTreeDataSource;
#treeStore?: UmbMediaTypeTreeStore;
#detailSource: UmbMediaTypeDetailServerDataSource;
#detailStore?: UmbMediaTypeDetailStore;
#notificationService?: UmbNotificationService;
constructor(host: UmbControllerHostInterface) {
this.#host = host;
// TODO: figure out how spin up get the correct data source
this.#treeSource = new MediaTypeTreeServerDataSource(this.#host);
this.#detailSource = new UmbMediaTypeDetailServerDataSource(this.#host);
this.#init = Promise.all([
new UmbContextConsumerController(this.#host, UMB_MEDIA_TYPE_DETAIL_STORE_CONTEXT_TOKEN, (instance) => {
this.#detailStore = instance;
}),
new UmbContextConsumerController(this.#host, UMB_MEDIA_TYPE_TREE_STORE_CONTEXT_TOKEN, (instance) => {
this.#treeStore = instance;
}),
new UmbContextConsumerController(this.#host, UMB_NOTIFICATION_SERVICE_CONTEXT_TOKEN, (instance) => {
this.#notificationService = instance;
}),
]);
}
async requestRootTreeItems() {
await this.#init;
const { data, error } = await this.#treeSource.getRootItems();
if (data) {
this.#treeStore?.appendItems(data.items);
}
return { data, error, asObservable: () => this.#treeStore!.rootItems };
}
async requestTreeItemsOf(parentKey: string | null) {
await this.#init;
if (!parentKey) {
const error: ProblemDetailsModel = { title: 'Parent key is missing' };
return { data: undefined, error };
}
const { data, error } = await this.#treeSource.getChildrenOf(parentKey);
if (data) {
this.#treeStore?.appendItems(data.items);
}
return { data, error, asObservable: () => this.#treeStore!.childrenOf(parentKey) };
}
async requestTreeItems(keys: Array<string>) {
await this.#init;
if (!keys) {
const error: ProblemDetailsModel = { title: 'Keys are missing' };
return { data: undefined, error };
}
const { data, error } = await this.#treeSource.getItems(keys);
return { data, error, asObservable: () => this.#treeStore!.items(keys) };
}
async rootTreeItems() {
await this.#init;
return this.#treeStore!.rootItems;
}
async treeItemsOf(parentKey: string | null) {
await this.#init;
return this.#treeStore!.childrenOf(parentKey);
}
async treeItems(keys: Array<string>) {
await this.#init;
return this.#treeStore!.items(keys);
}
// DETAILS
async createDetailsScaffold() {
await this.#init;
return this.#detailSource.createScaffold();
}
async requestDetails(key: string) {
await this.#init;
// TODO: should we show a notification if the key is missing?
// Investigate what is best for Acceptance testing, cause in that perspective a thrown error might be the best choice?
if (!key) {
const error: ProblemDetailsModel = { title: 'Key is missing' };
return { error };
}
const { data, error } = await this.#detailSource.get(key);
if (data) {
this.#detailStore?.append(data);
}
return { data, error };
}
async delete(key: string) {
await this.#init;
return this.#detailSource.delete(key);
}
async saveDetail(mediaType: MediaTypeDetails) {
await this.#init;
// TODO: should we show a notification if the media type is missing?
// Investigate what is best for Acceptance testing, cause in that perspective a thrown error might be the best choice?
if (!mediaType || !mediaType.key) {
const error: ProblemDetailsModel = { title: 'Media Type is missing' };
return { error };
}
const { error } = await this.#detailSource.update(mediaType);
if (!error) {
const notification = { data: { message: `Media type '${mediaType.name}' saved` } };
this.#notificationService?.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
// Consider notify a workspace if a media type is updated in the store while someone is editing it.
this.#detailStore?.append(mediaType);
this.#treeStore?.updateItem(mediaType.key, { name: mediaType.name });
// TODO: would be nice to align the stores on methods/methodNames.
return { error };
}
async createDetail(mediaType: MediaTypeDetails) {
await this.#init;
if (!mediaType.name) {
const error: ProblemDetailsModel = { title: 'Name is missing' };
return { error };
}
const { data, error } = await this.#detailSource.insert(mediaType);
if (!error) {
const notification = { data: { message: `Media type '${mediaType.name}' created` } };
this.#notificationService?.peek('positive', notification);
}
return { data, error };
}
async move() {
alert('move me!');
}
async copy() {
alert('copy me');
}
}

View File

@@ -0,0 +1,25 @@
import { UmbContextToken } from '@umbraco-cms/context-api';
import { UmbTreeStoreBase } from '@umbraco-cms/store';
import type { UmbControllerHostInterface } from '@umbraco-cms/controller';
/**
* @export
* @class UmbMediaTypeTreeStore
* @extends {UmbTreeStoreBase}
* @description - Tree Data Store for Media Types
*/
export class UmbMediaTypeTreeStore extends UmbTreeStoreBase {
/**
* Creates an instance of UmbMediaTypeTreeStore.
* @param {UmbControllerHostInterface} host
* @memberof UmbMediaTypeTreeStore
*/
constructor(host: UmbControllerHostInterface) {
super(host, UMB_MEDIA_TYPE_TREE_STORE_CONTEXT_TOKEN.toString());
}
}
export const UMB_MEDIA_TYPE_TREE_STORE_CONTEXT_TOKEN = new UmbContextToken<UmbMediaTypeTreeStore>(
UmbMediaTypeTreeStore.name
);

View File

@@ -0,0 +1,115 @@
import { MediaTypeDetailDataSource } from './media-type.details.server.data.interface';
import { ProblemDetailsModel } from '@umbraco-cms/backend-api';
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
import type { MediaTypeDetails } from '@umbraco-cms/models';
import { tryExecuteAndNotify } from '@umbraco-cms/resources';
/**
* @description - A data source for the Media Type detail that fetches data from the server
* @export
* @class UmbMediaTypeDetailServerDataSource
* @implements {MediaTypeDetailDataSource}
*/
export class UmbMediaTypeDetailServerDataSource implements MediaTypeDetailDataSource {
#host: UmbControllerHostInterface;
constructor(host: UmbControllerHostInterface) {
this.#host = host;
}
/**
* @description - Creates a new MediaType scaffold
* @return {*}
* @memberof UmbMediaTypeDetailServerDataSource
*/
async createScaffold() {
const data: MediaTypeDetails = {
name: '',
} as MediaTypeDetails;
return { data };
}
/**
* @description - Fetches a MediaType with the given key from the server
* @param {string} key
* @return {*}
* @memberof UmbMediaTypeDetailServerDataSource
*/
get(key: string) {
//return tryExecuteAndNotify(this.#host, MediaTypeResource.getMediaTypeByKey({ key })) as any;
// TODO: use backend cli when available.
return tryExecuteAndNotify(this.#host, fetch(`/umbraco/management/api/v1/media-type/${key}`)) as any;
}
/**
* @description - Updates a MediaType on the server
* @param {MediaTypeDetails} MediaType
* @return {*}
* @memberof UmbMediaTypeDetailServerDataSource
*/
async update(mediaType: MediaTypeDetails) {
if (!mediaType.key) {
const error: ProblemDetailsModel = { title: 'MediaType key is missing' };
return { error };
}
const payload = { key: mediaType.key, requestBody: mediaType };
//return tryExecuteAndNotify(this.#host, MediaTypeResource.putMediaTypeByKey(payload));
// TODO: use backend cli when available.
return tryExecuteAndNotify(
this.#host,
fetch(`/umbraco/management/api/v1/media-type/${mediaType.key}`, {
method: 'PUT',
body: JSON.stringify(payload),
headers: {
'Content-Type': 'application/json',
},
})
) as any;
}
/**
* @description - Inserts a new MediaType on the server
* @param {MediaTypeDetails} data
* @return {*}
* @memberof UmbMediaTypeDetailServerDataSource
*/
async insert(data: MediaTypeDetails) {
//return tryExecuteAndNotify(this.#host, MediaTypeResource.postMediaType({ requestBody: data }));
// TODO: use backend cli when available.
return tryExecuteAndNotify(
this.#host,
fetch(`/umbraco/management/api/v1/media-type/`, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
},
})
) as any;
}
/**
* @description - Deletes a MediaType on the server
* @param {string} key
* @return {*}
* @memberof UmbMediaTypeDetailServerDataSource
*/
async delete(key: string) {
if (!key) {
const error: ProblemDetailsModel = { title: 'Key is missing' };
return { error };
}
//return await tryExecuteAndNotify(this.#host, MediaTypeResource.deleteMediaTypeByKey({ key }));
// TODO: use backend cli when available.
return tryExecuteAndNotify(
this.#host,
fetch(`/umbraco/management/api/v1/media-type/${key}`, {
method: 'DELETE',
})
) as any;
}
}

View File

@@ -0,0 +1,10 @@
import type { DataSourceResponse, MediaTypeDetails } from '@umbraco-cms/models';
// TODO => Use models when they exist
export interface MediaTypeDetailDataSource {
createScaffold(parentKey: string): Promise<DataSourceResponse<MediaTypeDetails>>;
get(key: string): Promise<DataSourceResponse<MediaTypeDetails>>;
insert(data: any): Promise<DataSourceResponse>;
update(data: any): Promise<DataSourceResponse>;
delete(key: string): Promise<DataSourceResponse>;
}

View File

@@ -0,0 +1,72 @@
import { MediaTypeResource, ProblemDetailsModel } from '@umbraco-cms/backend-api';
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
import { RepositoryTreeDataSource } from '@umbraco-cms/repository';
import { tryExecuteAndNotify } from '@umbraco-cms/resources';
/**
* A data source for the MediaType tree that fetches data from the server
* @export
* @class MediaTypeTreeServerDataSource
* @implements {MediaTypeTreeDataSource}
*/
export class MediaTypeTreeServerDataSource implements RepositoryTreeDataSource {
#host: UmbControllerHostInterface;
/**
* Creates an instance of MediaTypeTreeDataSource.
* @param {UmbControllerHostInterface} host
* @memberof MediaTypeTreeDataSource
*/
constructor(host: UmbControllerHostInterface) {
this.#host = host;
}
/**
* Fetches the root items for the tree from the server
* @return {*}
* @memberof MediaTypeTreeServerDataSource
*/
async getRootItems() {
return tryExecuteAndNotify(this.#host, MediaTypeResource.getTreeMediaTypeRoot({}));
}
/**
* Fetches the children of a given parent key from the server
* @param {(string | null)} parentKey
* @return {*}
* @memberof MediaTypeTreeServerDataSource
*/
async getChildrenOf(parentKey: string | null) {
if (!parentKey) {
const error: ProblemDetailsModel = { title: 'Parent key is missing' };
return { error };
}
return tryExecuteAndNotify(
this.#host,
MediaTypeResource.getTreeMediaTypeChildren({
parentKey,
})
);
}
/**
* Fetches the items for the given keys from the server
* @param {Array<string>} keys
* @return {*}
* @memberof MediaTypeTreeServerDataSource
*/
async getItems(keys: Array<string>) {
if (!keys || keys.length === 0) {
const error: ProblemDetailsModel = { title: 'Keys are missing' };
return { error };
}
return tryExecuteAndNotify(
this.#host,
MediaTypeResource.getTreeMediaTypeItem({
key: keys,
})
);
}
}

View File

@@ -1,4 +1,4 @@
import { UMB_DATA_TYPE_TREE_STORE_CONTEXT_TOKEN } from '../media-type.tree.store';
import { UmbMediaTypeRepository } from '../repository/media-type.repository';
import type { ManifestTree, ManifestTreeItemAction } from '@umbraco-cms/models';
const tree: ManifestTree = {
@@ -6,7 +6,7 @@ const tree: ManifestTree = {
alias: 'Umb.Tree.MediaTypes',
name: 'Media Types Tree',
meta: {
storeAlias: UMB_DATA_TYPE_TREE_STORE_CONTEXT_TOKEN.toString(),
repository: UmbMediaTypeRepository
},
};

View File

@@ -0,0 +1,67 @@
import { UmbWorkspaceContext } from '../../../shared/components/workspace/workspace-context/workspace-context';
import { UmbWorkspaceEntityContextInterface } from '../../../shared/components/workspace/workspace-context/workspace-entity-context.interface';
import { UmbMediaTypeRepository } from '../repository/media-type.repository';
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
import { ObjectState } from '@umbraco-cms/observable-api';
import type { MediaTypeDetails } from '@umbraco-cms/models';
type EntityType = MediaTypeDetails;
export class UmbWorkspaceMediaTypeContext
extends UmbWorkspaceContext
implements UmbWorkspaceEntityContextInterface<EntityType | undefined>
{
#host: UmbControllerHostInterface;
#repo: UmbMediaTypeRepository;
#data = new ObjectState<MediaTypeDetails | undefined>(undefined);
data = this.#data.asObservable();
name = this.#data.getObservablePart((data) => data?.name);
constructor(host: UmbControllerHostInterface) {
super(host);
this.#host = host;
this.#repo = new UmbMediaTypeRepository(this.#host);
}
getData() {
return this.#data.getValue();
}
getEntityKey() {
return this.getData()?.key || '';
}
getEntityType() {
return 'media-type';
}
setName(name: string) {
this.#data.update({ name });
}
setPropertyValue(alias: string, value: string) {
// TODO => Implement setPropertyValue
}
async load(entityKey: string) {
const { data } = await this.#repo.requestDetails(entityKey);
if (data) {
this.#data.next(data);
}
}
async createScaffold() {
const { data } = await this.#repo.createDetailsScaffold();
if (!data) return;
this.#data.next(data);
}
async save() {
if (!this.#data.value) return;
this.#repo.saveDetail(this.#data.value);
}
public destroy(): void {
this.#data.complete();
}
}

View File

@@ -1,27 +1,71 @@
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { css, html, LitElement } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import '../../../shared/components/workspace/workspace-layout/workspace-layout.element';
import { css, html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { UUIInputElement, UUIInputEvent } from '@umbraco-ui/uui';
import { UmbWorkspaceEntityElement } from '../../../../backoffice/shared/components/workspace/workspace-entity-element.interface';
import { UmbWorkspaceMediaTypeContext } from './media-type-workspace.context';
import { UmbLitElement } from '@umbraco-cms/element';
@customElement('umb-media-type-workspace')
export class UmbMediaTypeWorkspaceElement extends LitElement {
export class UmbMediaTypeWorkspaceElement extends UmbLitElement implements UmbWorkspaceEntityElement {
static styles = [
UUITextStyles,
css`
:host {
display: block;
#header {
display: flex;
padding: 0 var(--uui-size-space-6);
gap: var(--uui-size-space-4);
width: 100%;
}
uui-input {
width: 100%;
height: 100%;
}
`,
];
@state()
private _unique?: string;
@state()
private _mediaTypeName?: string | null = '';
@property()
id!: string;
#workspaceContext = new UmbWorkspaceMediaTypeContext(this);
public load(entityKey: string) {
this.#workspaceContext.load(entityKey);
this._unique = entityKey;
}
public create() {
this.#workspaceContext.createScaffold();
}
async connectedCallback() {
super.connectedCallback();
this.observe(this.#workspaceContext.name, (name) => {
this._mediaTypeName = name;
});
}
// TODO. find a way where we don't have to do this for all Workspaces.
#handleInput(event: UUIInputEvent) {
if (event instanceof UUIInputEvent) {
const target = event.composedPath()[0] as UUIInputElement;
if (typeof target?.value === 'string') {
this.#workspaceContext.setName(target.value);
}
}
}
render() {
return html`<umb-workspace-layout alias="Umb.Workspace.MediaType">Media Type Workspace</umb-workspace-layout>`;
return html`<umb-workspace-layout alias="Umb.Workspace.MediaType">
<uui-input id="header" slot="header" .value=${this._unique} @input="${this.#handleInput}"></uui-input>
</umb-workspace-layout>`;
}
}

View File

@@ -2,7 +2,6 @@ import { UUIInputElement, UUIInputEvent } from '@umbraco-ui/uui';
import { UUITextStyles } from '@umbraco-ui/uui-css/lib';
import { css, html } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import { distinctUntilChanged } from 'rxjs';
import { UmbWorkspaceDataTypeContext } from './data-type-workspace.context';
import { UmbLitElement } from '@umbraco-cms/element';
@@ -29,23 +28,23 @@ export class UmbDataTypeWorkspaceElement extends UmbLitElement {
`,
];
private _workspaceContext: UmbWorkspaceDataTypeContext = new UmbWorkspaceDataTypeContext(this);
public load(value: string) {
this._workspaceContext?.load(value);
//this._unique = entityKey;
}
public create(parentKey: string | null) {
this._workspaceContext.createScaffold(parentKey);
}
#workspaceContext: UmbWorkspaceDataTypeContext = new UmbWorkspaceDataTypeContext(this);
@state()
private _dataTypeName = '';
public load(value: string) {
this.#workspaceContext?.load(value);
//this._unique = entityKey;
}
public create(parentKey: string | null) {
this.#workspaceContext.createScaffold(parentKey);
}
constructor() {
super();
this.observe(this._workspaceContext.name, (dataTypeName) => {
this.observe(this.#workspaceContext.name, (dataTypeName) => {
if (dataTypeName !== this._dataTypeName) {
this._dataTypeName = dataTypeName ?? '';
}
@@ -53,12 +52,12 @@ export class UmbDataTypeWorkspaceElement extends UmbLitElement {
}
// TODO. find a way where we don't have to do this for all Workspaces.
private _handleInput(event: UUIInputEvent) {
#handleInput(event: UUIInputEvent) {
if (event instanceof UUIInputEvent) {
const target = event.composedPath()[0] as UUIInputElement;
if (typeof target?.value === 'string') {
this._workspaceContext.setName(target.value);
this.#workspaceContext.setName(target.value);
}
}
}
@@ -66,7 +65,7 @@ export class UmbDataTypeWorkspaceElement extends UmbLitElement {
render() {
return html`
<umb-workspace-layout alias="Umb.Workspace.DataType">
<uui-input id="header" slot="header" .value=${this._dataTypeName} @input="${this._handleInput}"></uui-input>
<uui-input id="header" slot="header" .value=${this._dataTypeName} @input="${this.#handleInput}"></uui-input>
</umb-workspace-layout>
`;
}

View File

@@ -8,7 +8,7 @@ import type { DictionaryDetails } from '@umbraco-cms/models';
* @export
* @class UmbDictionaryDetailStore
* @extends {UmbStoreBase}
* @description - Details Data Store for Data Types
* @description - Details Data Store for Dictionary
*/
export class UmbDictionaryDetailStore
extends UmbStoreBase

View File

@@ -1,7 +1,7 @@
import { DictionaryTreeServerDataSource } from './sources/dictionary.tree.server.data';
import { UmbDictionaryTreeStore, UMB_DICTIONARY_TREE_STORE_CONTEXT_TOKEN } from './dictionary.tree.store';
import { UmbDictionaryDetailStore, UMB_DICTIONARY_DETAIL_STORE_CONTEXT_TOKEN } from './dictionary.detail.store';
import { UmbDictionaryDetailServerDataSource } from './sources/dictionary.detail.server.data';
import { UmbDictionaryDetailStore, UMB_DICTIONARY_DETAIL_STORE_CONTEXT_TOKEN } from './dictionary.detail.store';
import { UmbControllerHostInterface } from '@umbraco-cms/controller';
import { UmbContextConsumerController } from '@umbraco-cms/context-api';
import { RepositoryTreeDataSource, UmbTreeRepository } from '@umbraco-cms/repository';

View File

@@ -6,7 +6,7 @@ import { UmbControllerHostInterface } from '@umbraco-cms/controller';
* @export
* @class UmbDictionaryTreeStore
* @extends {UmbTreeStoreBase}
* @description - Tree Data Store for Data Types
* @description - Tree Data Store for Dictionary
*/
export class UmbDictionaryTreeStore extends UmbTreeStoreBase {