fixing types

This commit is contained in:
Mads Rasmussen
2024-05-13 19:56:33 +02:00
parent d2239b788a
commit 8322eb7de3
10 changed files with 113 additions and 61 deletions

View File

@@ -1,5 +1,5 @@
import type { UmbVariantStructureItemModel } from './types.js';
import type { UmbTreeRepository, UmbUniqueTreeRootModel } from '@umbraco-cms/backoffice/tree';
import type { UmbTreeItemModel, UmbTreeRepository, UmbTreeRootModel } from '@umbraco-cms/backoffice/tree';
import { createExtensionApiByAlias } from '@umbraco-cms/backoffice/extension-registry';
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UMB_VARIANT_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
@@ -46,7 +46,7 @@ export abstract class UmbMenuVariantTreeStructureWorkspaceContextBase extends Um
const unique = (await this.observe(uniqueObservable, () => {})?.asPromise()) as string;
if (!unique) throw new Error('Unique is not available');
const treeRepository = await createExtensionApiByAlias<UmbTreeRepository<any, UmbUniqueTreeRootModel>>(
const treeRepository = await createExtensionApiByAlias<UmbTreeRepository<UmbTreeItemModel, UmbTreeRootModel>>(
this,
this.#args.treeRepositoryAlias,
);

View File

@@ -1,5 +1,5 @@
import { UmbRequestReloadTreeItemChildrenEvent } from '../reload-tree-item-children/index.js';
import type { UmbTreeItemModelBase, UmbTreeStartNode } from '../types.js';
import type { UmbTreeItemModel, UmbTreeItemModelBase, UmbTreeRootModel, UmbTreeStartNode } from '../types.js';
import type { UmbTreeRepository } from '../data/tree-repository.interface.js';
import type { UmbTreeContext } from '../tree-context.interface.js';
import { type UmbActionEventContext, UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
@@ -17,11 +17,11 @@ import { UmbArrayState, UmbBooleanState, UmbObjectState } from '@umbraco-cms/bac
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
export class UmbDefaultTreeContext<TreeItemType extends UmbTreeItemModelBase>
extends UmbContextBase<UmbDefaultTreeContext<TreeItemType>>
export class UmbDefaultTreeContext<TreeItemType extends UmbTreeItemModel, TreeRootType extends UmbTreeRootModel>
extends UmbContextBase<UmbDefaultTreeContext<TreeItemType, TreeRootType>>
implements UmbTreeContext
{
#treeRoot = new UmbObjectState<TreeItemType | undefined>(undefined);
#treeRoot = new UmbObjectState<TreeRootType | undefined>(undefined);
treeRoot = this.#treeRoot.asObservable();
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -41,7 +41,7 @@ export class UmbDefaultTreeContext<TreeItemType extends UmbTreeItemModelBase>
startNode = this.#startNode.asObservable();
#manifest?: ManifestTree;
#repository?: UmbTreeRepository<TreeItemType>;
#repository?: UmbTreeRepository<TreeItemType, TreeRootType>;
#actionEventContext?: UmbActionEventContext;
#paging = {
@@ -173,7 +173,10 @@ export class UmbDefaultTreeContext<TreeItemType extends UmbTreeItemModelBase>
const { data } = startNode?.unique
? await this.#repository!.requestTreeItemsOf({
parentUnique: startNode.unique,
parent: {
unique: startNode.unique,
entityType: startNode.entityType,
},
skip,
take,
})
@@ -299,4 +302,6 @@ export class UmbDefaultTreeContext<TreeItemType extends UmbTreeItemModelBase>
export default UmbDefaultTreeContext;
export const UMB_DEFAULT_TREE_CONTEXT = new UmbContextToken<UmbDefaultTreeContext<any>>('UmbTreeContext');
export const UMB_DEFAULT_TREE_CONTEXT = new UmbContextToken<UmbDefaultTreeContext<UmbTreeItemModel, UmbTreeRootModel>>(
'UmbTreeContext',
);

View File

@@ -1,4 +1,10 @@
import type { UmbTreeItemModelBase, UmbTreeSelectionConfiguration, UmbTreeStartNode } from '../types.js';
import type {
UmbTreeItemModel,
UmbTreeItemModelBase,
UmbTreeRootModel,
UmbTreeSelectionConfiguration,
UmbTreeStartNode,
} from '../types.js';
import type { UmbDefaultTreeContext } from './default-tree.context.js';
import { UMB_DEFAULT_TREE_CONTEXT } from './default-tree.context.js';
import type { PropertyValueMap } from '@umbraco-cms/backoffice/external/lit';
@@ -32,10 +38,10 @@ export class UmbDefaultTreeElement extends UmbLitElement {
filter: (item: UmbTreeItemModelBase) => boolean = () => true;
@state()
private _rootItems: UmbTreeItemModelBase[] = [];
private _rootItems: UmbTreeItemModel[] = [];
@state()
private _treeRoot?: UmbTreeItemModelBase;
private _treeRoot?: UmbTreeRootModel;
@state()
private _currentPage = 1;
@@ -43,7 +49,7 @@ export class UmbDefaultTreeElement extends UmbLitElement {
@state()
private _totalPages = 1;
#treeContext?: UmbDefaultTreeContext<UmbTreeItemModelBase>;
#treeContext?: UmbDefaultTreeContext<UmbTreeItemModel, UmbTreeRootModel>;
#init: Promise<unknown>;
constructor() {

View File

@@ -1,6 +1,6 @@
import type { UmbTreeItemContext } from '../tree-item-context.interface.js';
import { UMB_DEFAULT_TREE_CONTEXT, type UmbDefaultTreeContext } from '../../default/default-tree.context.js';
import type { UmbTreeItemModel } from '../../types.js';
import type { UmbTreeItemModel, UmbTreeRootModel } from '../../types.js';
import { UmbRequestReloadTreeItemChildrenEvent } from '../../reload-tree-item-children/index.js';
import { map } from '@umbraco-cms/backoffice/external/rxjs';
import { UMB_SECTION_CONTEXT, UMB_SECTION_SIDEBAR_CONTEXT } from '@umbraco-cms/backoffice/section';
@@ -17,7 +17,10 @@ import type { UmbEntityActionEvent } from '@umbraco-cms/backoffice/entity-action
import { UmbPaginationManager, debounce } from '@umbraco-cms/backoffice/utils';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
export abstract class UmbTreeItemContextBase<TreeItemType extends UmbTreeItemModel>
export abstract class UmbTreeItemContextBase<
TreeItemType extends UmbTreeItemModel,
TreeRootType extends UmbTreeRootModel,
>
extends UmbContextBase<UmbTreeItemContext<TreeItemType>>
implements UmbTreeItemContext<TreeItemType>
{
@@ -59,7 +62,7 @@ export abstract class UmbTreeItemContextBase<TreeItemType extends UmbTreeItemMod
#path = new UmbStringState('');
readonly path = this.#path.asObservable();
treeContext?: UmbDefaultTreeContext<TreeItemType>;
treeContext?: UmbDefaultTreeContext<TreeItemType, TreeRootType>;
#sectionContext?: UmbSectionContext;
#sectionSidebarContext?: UmbSectionSidebarContext;
#actionEventContext?: UmbActionEventContext;
@@ -226,7 +229,7 @@ export abstract class UmbTreeItemContextBase<TreeItemType extends UmbTreeItemMod
this.#sectionSidebarContext = instance;
});
this.consumeContext(UMB_DEFAULT_TREE_CONTEXT, (treeContext: UmbDefaultTreeContext<TreeItemType>) => {
this.consumeContext(UMB_DEFAULT_TREE_CONTEXT, (treeContext) => {
this.treeContext = treeContext;
this.#observeIsSelectable();
this.#observeIsSelected();

View File

@@ -1,10 +1,11 @@
import { UmbTreeItemContextBase } from '../tree-item-base/index.js';
import type { UmbTreeItemModel } from '../../types.js';
import type { UmbTreeItemModel, UmbTreeRootModel } from '../../types.js';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
export class UmbDefaultTreeItemContext<
TreeItemModelType extends UmbTreeItemModel,
> extends UmbTreeItemContextBase<TreeItemModelType> {
TreeItemType extends UmbTreeItemModel,
TreeRootType extends UmbTreeRootModel,
> extends UmbTreeItemContextBase<TreeItemType, TreeRootType> {
constructor(host: UmbControllerHost) {
super(host);
}

View File

@@ -1,9 +1,12 @@
import type { UmbDocumentTreeItemModel } from '../types.js';
import type { UmbDocumentTreeItemModel, UmbDocumentTreeRootModel } from '../types.js';
import { UmbDefaultTreeItemContext } from '@umbraco-cms/backoffice/tree';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbIsTrashedEntityContext } from '@umbraco-cms/backoffice/recycle-bin';
export class UmbDocumentTreeItemContext extends UmbDefaultTreeItemContext<UmbDocumentTreeItemModel> {
export class UmbDocumentTreeItemContext extends UmbDefaultTreeItemContext<
UmbDocumentTreeItemModel,
UmbDocumentTreeRootModel
> {
// TODO: Provide this together with the EntityContext, ideally this takes part via a extension-type [NL]
#isTrashedContext = new UmbIsTrashedEntityContext(this);

View File

@@ -1,35 +1,37 @@
import type { UmbMediaPathModel } from '../types.js';
import type { UmbMediaDetailModel } from '../../../types.js';
import { UmbMediaDetailRepository } from '../../../repository/index.js';
import { UmbMediaTreeRepository } from '../../../tree/media-tree.repository.js';
import { UmbMediaTreeRepository } from '../../../tree/index.js';
import { UMB_MEDIA_ROOT_ENTITY_TYPE } from '../../../entity.js';
import { css, html, customElement, state, repeat, property } from '@umbraco-cms/backoffice/external/lit';
import type { UUIInputElement, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
import { UmbId } from '@umbraco-cms/backoffice/id';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { getUmbracoFolderUnique } from '@umbraco-cms/backoffice/media-type';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
const root = { name: 'Media', unique: null };
// TODO: get root from tree repository
const root = { name: 'Media', unique: null, entityType: UMB_MEDIA_ROOT_ENTITY_TYPE };
@customElement('umb-media-picker-folder-path')
export class UmbMediaPickerFolderPathElement extends UmbLitElement {
#mediaTreeRepository = new UmbMediaTreeRepository(this); // used to get file structure
#mediaDetailRepository = new UmbMediaDetailRepository(this); // used to create folders
@property()
public set currentPath(value: string | null) {
if (value !== this._currentPath) {
this._currentPath = value;
@property({ type: Object, attribute: false })
public set currentMedia(value: UmbEntityModel | undefined) {
if (value !== this._currentMedia) {
this._currentMedia = value;
this.#loadPath();
this.dispatchEvent(new UmbChangeEvent());
}
}
public get currentPath() {
return this._currentPath;
public get currentMedia() {
return this._currentMedia;
}
@state()
private _currentPath: string | null = null;
private _currentMedia: UmbEntityModel | undefined;
@state()
private _paths: Array<UmbMediaPathModel> = [root];
@@ -43,21 +45,32 @@ export class UmbMediaPickerFolderPathElement extends UmbLitElement {
}
async #loadPath() {
if (this.currentPath) {
const unique = this._currentMedia?.unique;
const entityType = this._currentMedia?.entityType;
if (unique && entityType) {
const { data } = await this.#mediaTreeRepository.requestTreeItemAncestors({
descendantUnique: this.currentPath,
treeItem: {
unique,
entityType,
},
});
if (data) {
this._paths = [root, ...data.map((item) => ({ name: item.name, unique: item.unique }))];
} else {
this._paths = [root];
this._paths = [
root,
...data.map((item) => ({ name: item.name, unique: item.unique, entityType: item.entityType })),
];
return;
}
}
this._paths = [root];
}
#goToFolder(unique: string | null) {
this._paths = [...this._paths].slice(0, this._paths.findIndex((path) => path.unique === unique) + 1);
this.currentPath = unique;
#goToFolder(entity: UmbEntityModel) {
this._paths = [...this._paths].slice(0, this._paths.findIndex((path) => path.unique === entity.unique) + 1);
this.currentMedia = entity;
}
#focusFolderInput() {
@@ -102,9 +115,10 @@ export class UmbMediaPickerFolderPathElement extends UmbLitElement {
const name = data.variants[0].name;
const unique = data.unique;
const entityType = data.entityType;
this._paths = [...this._paths, { name, unique }];
this.currentPath = unique;
this._paths = [...this._paths, { name, unique, entityType }];
this.currentMedia = { unique, entityType };
}
render() {
@@ -116,8 +130,8 @@ export class UmbMediaPickerFolderPathElement extends UmbLitElement {
html`<uui-button
compact
.label=${path.name}
?disabled=${this.currentPath == path.unique}
@click=${() => this.#goToFolder(path.unique)}></uui-button
?disabled=${this.currentMedia?.unique === path.unique}
@click=${() => this.#goToFolder({ unique: path.unique, entityType: path.entityType })}></uui-button
>/`,
)}${this._typingNewFolder
? html`<uui-input

View File

@@ -1,11 +1,13 @@
import { type UmbMediaItemModel, UmbMediaItemRepository, UmbMediaUrlRepository } from '../../repository/index.js';
import { UmbMediaTreeRepository } from '../../tree/media-tree.repository.js';
import { UMB_MEDIA_ROOT_ENTITY_TYPE } from '../../entity.js';
import type { UmbMediaCardItemModel } from './types.js';
import type { UmbMediaPickerFolderPathElement } from './components/media-picker-folder-path.element.js';
import type { UmbMediaPickerModalData, UmbMediaPickerModalValue } from './media-picker-modal.token.js';
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
import { css, html, customElement, state, repeat, ifDefined } from '@umbraco-cms/backoffice/external/lit';
import type { UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
@customElement('umb-media-picker-modal')
export class UmbMediaPickerModalElement extends UmbModalBaseElement<UmbMediaPickerModalData, UmbMediaPickerModalValue> {
@@ -25,17 +27,27 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement<UmbMediaPick
private _searchQuery = '';
@state()
private _currentNode: string | null = null;
connectedCallback(): void {
private _currentMediaEntity: UmbEntityModel = { unique: null, entityType: UMB_MEDIA_ROOT_ENTITY_TYPE };
async connectedCallback(): Promise<void> {
super.connectedCallback();
this._currentNode = this.data?.startNode ?? null;
if (this.data?.startNode) {
const { data } = await this.#mediaItemRepository.requestItems([this.data.startNode]);
if (data?.length) {
this._currentMediaEntity = { unique: data[0].unique, entityType: data[0].entityType };
}
}
this.#loadMediaFolder();
}
async #loadMediaFolder() {
const { data } = await this.#mediaTreeRepository.requestTreeItemsOf({
parentUnique: this._currentNode,
parent: {
unique: this._currentMediaEntity.unique,
entityType: this._currentMediaEntity.entityType,
},
skip: 0,
take: 100,
});
@@ -53,13 +65,15 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement<UmbMediaPick
const url = data?.find((media) => media.unique === item.unique)?.url;
const extension = url?.split('.').pop();
//TODO Eventually we will get a renderable img from the server. Use this for the url. [LI]
return { name: item.name, unique: item.unique, url, extension };
return { name: item.name, unique: item.unique, url, extension, entityType: item.entityType };
});
}
#onOpen(item: UmbMediaCardItemModel) {
this._currentNode = item.unique!;
this._currentMediaEntity = {
unique: item.unique,
entityType: UMB_MEDIA_ROOT_ENTITY_TYPE,
};
this.#loadMediaFolder();
}
@@ -107,7 +121,10 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement<UmbMediaPick
}
#onPathChange(e: CustomEvent) {
this._currentNode = (e.target as UmbMediaPickerFolderPathElement).currentPath;
this._currentMediaEntity = (e.target as UmbMediaPickerFolderPathElement).currentMedia || {
unique: null,
entityType: UMB_MEDIA_ROOT_ENTITY_TYPE,
};
this.#loadMediaFolder();
}
@@ -129,7 +146,7 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement<UmbMediaPick
#renderBody() {
return html`${this.#renderToolbar()}
<umb-dropzone id="dropzone" @change=${() => this.#loadMediaFolder()} .parentUnique=${this._currentNode}></umb-dropzone>
<umb-dropzone id="dropzone" @change=${() => this.#loadMediaFolder()} .parentUnique=${this._currentMediaEntity.unique}></umb-dropzone>
${
!this._mediaFilteredList.length
? html`<div class="container"><p>${this.localize.term('content_listViewNoItems')}</p></div>`
@@ -146,7 +163,7 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement<UmbMediaPick
#renderToolbar() {
return html`<div id="toolbar">
<umb-media-picker-create-item .node=${this._currentNode}></umb-media-picker-create-item>
<umb-media-picker-create-item .node=${this._currentMediaEntity.unique}></umb-media-picker-create-item>
<div id="search">
<uui-input
label=${this.localize.term('general_search')}
@@ -182,7 +199,7 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement<UmbMediaPick
#renderPath() {
return html`<umb-media-picker-folder-path
slot="footer-info"
.currentPath=${this._currentNode}
.currentPath=${this._currentMediaEntity.unique}
@change=${this.#onPathChange}></umb-media-picker-folder-path>`;
}

View File

@@ -1,11 +1,14 @@
import type { UmbMediaEntityType } from '../../entity.js';
import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity';
export interface UmbMediaCardItemModel {
name: string;
unique: string;
entityType: UmbMediaEntityType;
url?: string;
extension?: string;
}
export interface UmbMediaPathModel {
export interface UmbMediaPathModel extends UmbEntityModel {
name: string;
unique: string | null;
}

View File

@@ -1,9 +1,9 @@
import type { UmbMediaTreeItemModel } from '../types.js';
import type { UmbMediaTreeItemModel, UmbMediaTreeRootModel } from '../types.js';
import { UmbDefaultTreeItemContext } from '@umbraco-cms/backoffice/tree';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbIsTrashedEntityContext } from '@umbraco-cms/backoffice/recycle-bin';
export class UmbMediaTreeItemContext extends UmbDefaultTreeItemContext<UmbMediaTreeItemModel> {
export class UmbMediaTreeItemContext extends UmbDefaultTreeItemContext<UmbMediaTreeItemModel, UmbMediaTreeRootModel> {
#isTrashedContext = new UmbIsTrashedEntityContext(this);
constructor(host: UmbControllerHost) {