V15: New dropzone component available for the Backoffice (#18753)
* create a symlink between local Client .vscode snippets and global snippets for ease of use * fix: no need to specify `Element` in the snippet as that is pulled from the filename Because of our convention with `x.element.ts` you would have ended up with `UmbXElementElement` * feat: adds new component `umb-input-dropzone` * docs(storybook): more stories * feat: construct the temporary files centrally along with an `AbortController` and use its signal * feat: makes UmbInputDropzone form aware * feat: introduces a change event * chore: temporary changes before changing upload field * feat: adds default slot * docs: adds jsdocs * feat: adds more properties * feat: adds dashed styling * feat: adds multiple support * feat: allows to cancel file * feat: separate **cancel** and **remove** * fix stylibg * move dropzone element * move input-dropzone into dropzone package * feat: introduces a 'dropzone' package * import for backward compatibility * remove ambigious export * reexport everything from dropzone * fix import * cleanup test files * use correct import paths * test: make sure folder exists before writing to it * adds export for modals * adds entrypoint for dropzone package * use the AbortController directly on the temporary file object * uses correct icon name * feat: adds ability to remove all files and cancel the request * feat: adds styling for the uploader and enables it to work in multiple mode with classes over id's * do not let the content exceed its boundaries * feat: formats progress with 2 decimals * feat: formats with 0 decimals * fix: returns cancel error * fix: maps cancel errors back to the uploadable item * fix: do not proceed with media items if the request was cancelled * chore: mark exports from media <- dropzone as deprecated * fix: use correct attribute and remove a todo with localizations * fix: use correct attribute and remove a todo with localizations * fix: allow to specify parent through attribute * feat: align attribute `disableFolderUpload` between dropzone components
This commit is contained in:
1
.vscode/lit.code-snippets
vendored
Symbolic link
1
.vscode/lit.code-snippets
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../src/Umbraco.Web.UI.Client/.vscode/lit.code-snippets
|
||||
@@ -8,7 +8,7 @@
|
||||
"import { UmbTextStyles } from '@umbraco-cms/backoffice/style';",
|
||||
"",
|
||||
"@customElement('umb-${TM_FILENAME_BASE/(.*)\\..+$/$1/}')",
|
||||
"export class Umb${TM_FILENAME_BASE/(.*)$/${1:/pascalcase}/}Element extends UmbLitElement {",
|
||||
"export class Umb${TM_FILENAME_BASE/(.*)$/${1:/pascalcase}/} extends UmbLitElement {",
|
||||
"\toverride render() {",
|
||||
"\t\treturn html`$0`;",
|
||||
"\t}",
|
||||
@@ -16,11 +16,11 @@
|
||||
"\tstatic override readonly styles = [UmbTextStyles, css``];",
|
||||
"}",
|
||||
"",
|
||||
"export { Umb${TM_FILENAME_BASE/(.*)$/${1:/pascalcase}/}Element as element };",
|
||||
"export { Umb${TM_FILENAME_BASE/(.*)$/${1:/pascalcase}/} as element };",
|
||||
"",
|
||||
"declare global {",
|
||||
"\tinterface HTMLElementTagNameMap {",
|
||||
"\t\t'umb-${TM_FILENAME_BASE/(.*)\\..+$/$1/}': Umb${TM_FILENAME_BASE/(.*)$/${1:/pascalcase}/}Element;",
|
||||
"\t\t'umb-${TM_FILENAME_BASE/(.*)\\..+$/$1/}': Umb${TM_FILENAME_BASE/(.*)$/${1:/pascalcase}/};",
|
||||
"\t}",
|
||||
"}",
|
||||
"",
|
||||
|
||||
@@ -91,8 +91,9 @@ export async function findUmbConstExports() {
|
||||
|
||||
const content = `export const foundConsts = [${foundConsts.join(',\n')}];`;
|
||||
|
||||
const outputPath = path.join(projectRoot, './utils/all-umb-consts/index.ts');
|
||||
fs.writeFileSync(outputPath, content);
|
||||
const outputPath = path.join(projectRoot, './utils/all-umb-consts');
|
||||
fs.mkdirSync(outputPath, { recursive: true });
|
||||
fs.writeFileSync(path.join(outputPath, 'index.ts'), content, {});
|
||||
|
||||
generatetestImportFile(projectRoot);
|
||||
|
||||
@@ -149,8 +150,9 @@ function generatetestImportFile(projectRoot) {
|
||||
];
|
||||
`
|
||||
|
||||
const outputPath = path.join(projectRoot, './utils/all-umb-consts/imports.ts');
|
||||
fs.writeFileSync(outputPath, content);
|
||||
const outputPath = path.join(projectRoot, './utils/all-umb-consts');
|
||||
fs.mkdirSync(outputPath, { recursive: true });
|
||||
fs.writeFileSync(path.join(outputPath, 'imports.ts'), content);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
"./document-blueprint": "./dist-cms/packages/documents/document-blueprints/index.js",
|
||||
"./document-type": "./dist-cms/packages/documents/document-types/index.js",
|
||||
"./document": "./dist-cms/packages/documents/documents/index.js",
|
||||
"./dropzone": "./dist-cms/packages/media/dropzone/index.js",
|
||||
"./entity-action": "./dist-cms/packages/core/entity-action/index.js",
|
||||
"./entity-bulk-action": "./dist-cms/packages/core/entity-bulk-action/index.js",
|
||||
"./entity-create-option-action": "./dist-cms/packages/core/entity-create-option-action/index.js",
|
||||
|
||||
@@ -71,7 +71,7 @@ export class UmbResourceController extends UmbControllerBase {
|
||||
*/
|
||||
if (isCancelError(error)) {
|
||||
// Cancelled - do nothing
|
||||
return {};
|
||||
return { error };
|
||||
} else {
|
||||
console.groupCollapsed('ApiError caught in UmbResourceController');
|
||||
console.error('Request failed', error.request);
|
||||
|
||||
@@ -11,6 +11,7 @@ import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
|
||||
import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization-api';
|
||||
import { UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification';
|
||||
import { formatBytes } from '@umbraco-cms/backoffice/utils';
|
||||
import { isCancelError } from '@umbraco-cms/backoffice/resources';
|
||||
|
||||
export class UmbTemporaryFileManager<
|
||||
UploadableItem extends UmbTemporaryFileModel = UmbTemporaryFileModel,
|
||||
@@ -62,6 +63,10 @@ export class UmbTemporaryFileManager<
|
||||
this.#queue.remove(uniques);
|
||||
}
|
||||
|
||||
removeAll() {
|
||||
this.#queue.setValue([]);
|
||||
}
|
||||
|
||||
async #handleQueue(options?: UmbUploadOptions<UploadableItem>): Promise<Array<UploadableItem>> {
|
||||
const filesCompleted: Array<UploadableItem> = [];
|
||||
const queue = this.#queue.getValue();
|
||||
@@ -152,9 +157,15 @@ export class UmbTemporaryFileManager<
|
||||
// Update progress in percent if a callback is provided
|
||||
if (item.onProgress) item.onProgress((evt.loaded / evt.total) * 100);
|
||||
},
|
||||
item.abortSignal,
|
||||
item.abortController?.signal ?? item.abortSignal,
|
||||
);
|
||||
const status = error ? TemporaryFileStatus.ERROR : TemporaryFileStatus.SUCCESS;
|
||||
let status = TemporaryFileStatus.SUCCESS;
|
||||
if (error) {
|
||||
status = TemporaryFileStatus.ERROR;
|
||||
if (isCancelError(error)) {
|
||||
status = TemporaryFileStatus.CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
this.#queue.updateOne(item.temporaryUnique, { ...item, status });
|
||||
return { ...item, status };
|
||||
|
||||
@@ -4,6 +4,7 @@ export enum TemporaryFileStatus {
|
||||
SUCCESS = 'success',
|
||||
WAITING = 'waiting',
|
||||
ERROR = 'error',
|
||||
CANCELLED = 'cancelled',
|
||||
}
|
||||
|
||||
export interface UmbTemporaryFileModel {
|
||||
@@ -11,7 +12,15 @@ export interface UmbTemporaryFileModel {
|
||||
temporaryUnique: string;
|
||||
status?: TemporaryFileStatus;
|
||||
onProgress?: (progress: number) => void;
|
||||
/**
|
||||
* The abort signal used to cancel the upload.
|
||||
* @deprecated Use {@link abortController} instead.
|
||||
*/
|
||||
abortSignal?: AbortSignal;
|
||||
/**
|
||||
* The abort controller used to cancel the upload.
|
||||
*/
|
||||
abortController?: AbortController;
|
||||
}
|
||||
|
||||
export type UmbQueueHandlerCallback<TItem extends UmbTemporaryFileModel> = (item: TItem) => Promise<void>;
|
||||
|
||||
@@ -6,7 +6,7 @@ import type {
|
||||
import { css, html, customElement, query, state, when } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
|
||||
import type { UmbDropzoneElement } from '@umbraco-cms/backoffice/media';
|
||||
import type { UmbDropzoneElement } from '@umbraco-cms/backoffice/dropzone';
|
||||
|
||||
interface UmbDocumentTypePreview {
|
||||
unique: string;
|
||||
@@ -134,13 +134,18 @@ export class UmbDocumentTypeImportModalLayout extends UmbModalBaseElement<
|
||||
() =>
|
||||
/**TODO Add localizations */
|
||||
html`<div id="wrapper">
|
||||
Drag and drop your file here
|
||||
<uui-button look="primary" label="or click here to choose a file" @click=${this.#onBrowse}></uui-button>
|
||||
<umb-localize key="media_dragAndDropYourFilesIntoTheArea"
|
||||
>Drag and drop your file(s) into the area
|
||||
</umb-localize>
|
||||
<uui-button
|
||||
look="primary"
|
||||
label="${this.localize.term('media_clickToUpload')}"
|
||||
@click=${this.#onBrowse}></uui-button>
|
||||
<umb-dropzone
|
||||
id="dropzone"
|
||||
accept=".udt"
|
||||
@complete=${this.#onUploadComplete}
|
||||
createAsTemporary></umb-dropzone>
|
||||
create-as-temporary
|
||||
@complete=${this.#onUploadComplete}></umb-dropzone>
|
||||
</div>`,
|
||||
)}
|
||||
`;
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { UmbDropzoneManager } from './dropzone-manager.class.js';
|
||||
import { UmbDropzoneSubmittedEvent } from './dropzone-submitted.event.js';
|
||||
import { UmbFileDropzoneItemStatus, type UmbUploadableItem } from './types.js';
|
||||
import { UmbDropzoneManager } from '../dropzone-manager.class.js';
|
||||
import { UmbDropzoneSubmittedEvent } from '../dropzone-submitted.event.js';
|
||||
import type { UmbUploadableItem } from '../types.js';
|
||||
import { UmbFileDropzoneItemStatus } from '../constants.js';
|
||||
import { css, customElement, html, ifDefined, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import type { UUIFileDropzoneElement, UUIFileDropzoneEvent } from '@umbraco-cms/backoffice/external/uui';
|
||||
|
||||
@customElement('umb-dropzone')
|
||||
export class UmbDropzoneElement extends UmbLitElement {
|
||||
@property({ attribute: false })
|
||||
@property({ attribute: 'parent-unique' })
|
||||
parentUnique: string | null = null;
|
||||
|
||||
@property({ type: Boolean })
|
||||
@property({ type: Boolean, attribute: 'create-as-temporary' })
|
||||
createAsTemporary: boolean = false;
|
||||
|
||||
@property({ type: String })
|
||||
@@ -23,12 +24,12 @@ export class UmbDropzoneElement extends UmbLitElement {
|
||||
disabled = false;
|
||||
|
||||
@property({ type: Boolean, attribute: 'disable-folder-upload', reflect: true })
|
||||
public get disableFolderUpload() {
|
||||
return this._disableFolderUpload;
|
||||
}
|
||||
public set disableFolderUpload(isAllowed: boolean) {
|
||||
this.#dropzoneManager.setIsFoldersAllowed(!isAllowed);
|
||||
}
|
||||
public get disableFolderUpload() {
|
||||
return this._disableFolderUpload;
|
||||
}
|
||||
private readonly _disableFolderUpload = false;
|
||||
|
||||
@state()
|
||||
@@ -130,6 +131,7 @@ export class UmbDropzoneElement extends UmbLitElement {
|
||||
id="dropzone"
|
||||
accept=${ifDefined(this.accept)}
|
||||
?multiple=${this.multiple}
|
||||
?disallowFolderUpload=${this.disableFolderUpload}
|
||||
@change=${this.#onDropFiles}
|
||||
label=${this.localize.term('media_dragAndDropYourFilesIntoTheArea')}></uui-file-dropzone>`;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './input-dropzone/input-dropzone.element.js';
|
||||
export * from './dropzone.element.js';
|
||||
@@ -0,0 +1,306 @@
|
||||
import { UmbDropzoneChangeEvent, UmbDropzoneManager, UmbDropzoneSubmittedEvent } from '../../index.js';
|
||||
import type { UmbUploadableItem } from '../../types.js';
|
||||
import { UmbFileDropzoneItemStatus } from '../../constants.js';
|
||||
import {
|
||||
css,
|
||||
customElement,
|
||||
html,
|
||||
ifDefined,
|
||||
nothing,
|
||||
property,
|
||||
query,
|
||||
repeat,
|
||||
state,
|
||||
when,
|
||||
} from '@umbraco-cms/backoffice/external/lit';
|
||||
import type { UUIFileDropzoneElement, UUIFileDropzoneEvent } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { formatBytes } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
|
||||
|
||||
/**
|
||||
* @element umb-input-dropzone
|
||||
* @fires ProgressEvent When the progress of the upload changes.
|
||||
* @fires UmbDropzoneChangeEvent When the upload is complete.
|
||||
* @fires UmbDropzoneSubmittedEvent When the upload is submitted.
|
||||
* @slot - The default slot.
|
||||
*/
|
||||
@customElement('umb-input-dropzone')
|
||||
export class UmbInputDropzoneElement extends UmbFormControlMixin<UmbUploadableItem[], typeof UmbLitElement>(
|
||||
UmbLitElement,
|
||||
) {
|
||||
/**
|
||||
* Comma-separated list of accepted mime types or file extensions.
|
||||
*/
|
||||
@property({ type: String })
|
||||
accept?: string;
|
||||
|
||||
/**
|
||||
* Determines if the dropzone should create temporary files or media items directly.
|
||||
*/
|
||||
@property({ type: Boolean, attribute: 'create-as-temporary' })
|
||||
createAsTemporary: boolean = false;
|
||||
|
||||
/**
|
||||
* Disable folder uploads.
|
||||
*/
|
||||
@property({ type: Boolean, attribute: 'disable-folder-upload', reflect: true })
|
||||
public set disableFolderUpload(isAllowed: boolean) {
|
||||
this.#manager.setIsFoldersAllowed(!isAllowed);
|
||||
}
|
||||
public get disableFolderUpload() {
|
||||
return this._disableFolderUpload;
|
||||
}
|
||||
private readonly _disableFolderUpload = false;
|
||||
|
||||
/**
|
||||
* Create the media item below this parent.
|
||||
* @description This is only used when `createAsTemporary` is `false`.
|
||||
*/
|
||||
@property({ type: String, attribute: 'parent-unique' })
|
||||
parentUnique: string | null = null;
|
||||
|
||||
/**
|
||||
* Disables the dropzone.
|
||||
* @description The dropzone will not accept any uploads.
|
||||
*/
|
||||
@property({ type: Boolean, reflect: true })
|
||||
disabled: boolean = false;
|
||||
|
||||
/**
|
||||
* Determines if the dropzone should accept multiple files.
|
||||
*/
|
||||
@property({ type: Boolean })
|
||||
multiple: boolean = false;
|
||||
|
||||
/**
|
||||
* The label for the dropzone.
|
||||
*/
|
||||
@property({ type: String })
|
||||
label = 'dropzone';
|
||||
|
||||
@query('#dropzone', true)
|
||||
private _dropzone?: UUIFileDropzoneElement;
|
||||
|
||||
@state()
|
||||
private _progressItems?: Array<UmbUploadableItem>;
|
||||
|
||||
#manager = new UmbDropzoneManager(this);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.observe(
|
||||
this.#manager.progress,
|
||||
(progress) =>
|
||||
this.dispatchEvent(new ProgressEvent('progress', { loaded: progress.completed, total: progress.total })),
|
||||
'_observeProgress',
|
||||
);
|
||||
|
||||
this.observe(
|
||||
this.#manager.progressItems,
|
||||
(progressItems) => {
|
||||
this._progressItems = [...progressItems];
|
||||
const waiting = this._progressItems.find((item) => item.status === UmbFileDropzoneItemStatus.WAITING);
|
||||
if (this._progressItems.length && !waiting) {
|
||||
this.value = [...this._progressItems];
|
||||
this.dispatchEvent(new UmbDropzoneChangeEvent(this._progressItems));
|
||||
}
|
||||
},
|
||||
'_observeProgressItems',
|
||||
);
|
||||
}
|
||||
|
||||
override render() {
|
||||
return html`
|
||||
<uui-file-dropzone
|
||||
id="dropzone"
|
||||
label=${this.label}
|
||||
accept=${ifDefined(this.accept)}
|
||||
?multiple=${this.multiple}
|
||||
?disabled=${this.disabled}
|
||||
?disallowFolderUpload=${this.disableFolderUpload}
|
||||
@change=${this.#onUpload}
|
||||
@click=${this.#handleBrowse}>
|
||||
<slot>
|
||||
<uui-button label=${this.localize.term('media_clickToUpload')} @click=${this.#handleBrowse}></uui-button>
|
||||
</slot>
|
||||
</uui-file-dropzone>
|
||||
${this.#renderUploader()}
|
||||
`;
|
||||
}
|
||||
|
||||
#renderUploader() {
|
||||
if (this.disabled) return nothing;
|
||||
if (!this._progressItems?.length) return nothing;
|
||||
|
||||
return html`
|
||||
<div id="uploader">
|
||||
${repeat(
|
||||
this._progressItems,
|
||||
(item) => item.unique,
|
||||
(item) => this.#renderPlaceholder(item),
|
||||
)}
|
||||
<uui-button
|
||||
id="uploader-clear"
|
||||
compact
|
||||
@click=${this.#handleRemove}
|
||||
label=${this.localize.term('content_uploadClear')}>
|
||||
<uui-icon name="icon-trash"></uui-icon>${this.localize.term('content_uploadClear')}
|
||||
</uui-button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
#renderPlaceholder(item: UmbUploadableItem) {
|
||||
const file = item.temporaryFile?.file;
|
||||
return html`
|
||||
<div class="placeholder">
|
||||
<div class="fileIcon">
|
||||
${when(
|
||||
item.status === UmbFileDropzoneItemStatus.COMPLETE,
|
||||
() => html`<umb-icon name="check" color="green"></umb-icon>`,
|
||||
)}
|
||||
${when(
|
||||
item.status === UmbFileDropzoneItemStatus.ERROR ||
|
||||
item.status === UmbFileDropzoneItemStatus.CANCELLED ||
|
||||
item.status === UmbFileDropzoneItemStatus.NOT_ALLOWED,
|
||||
() => html`<umb-icon name="wrong" color="red"></umb-icon>`,
|
||||
)}
|
||||
</div>
|
||||
<div class="fileDetails">
|
||||
<div class="fileName" title=${file?.name ?? ''}>${file?.name ?? ''}</div>
|
||||
<div class="fileSize">
|
||||
${formatBytes(file?.size ?? 0, { decimals: 2 })}:
|
||||
${this.localize.number(item.progress, { maximumFractionDigits: 0 })}%
|
||||
</div>
|
||||
${when(
|
||||
item.status === UmbFileDropzoneItemStatus.WAITING,
|
||||
() => html`<div class="progress"><uui-loader-bar progress=${item.progress}></uui-loader-bar></div>`,
|
||||
)}
|
||||
${when(
|
||||
item.status === UmbFileDropzoneItemStatus.ERROR,
|
||||
() => html`<div class="error">An error occured</div>`,
|
||||
)}
|
||||
${when(item.status === UmbFileDropzoneItemStatus.CANCELLED, () => html`<div class="error">Cancelled</div>`)}
|
||||
${when(
|
||||
item.status === UmbFileDropzoneItemStatus.NOT_ALLOWED,
|
||||
() => html`<div class="error">File type not allowed</div>`,
|
||||
)}
|
||||
</div>
|
||||
<div class="fileActions">
|
||||
${when(
|
||||
item.status === UmbFileDropzoneItemStatus.WAITING,
|
||||
() => html`
|
||||
<uui-button
|
||||
compact
|
||||
@click=${() => this.#handleCancel(item)}
|
||||
label=${this.localize.term('general_cancel')}>
|
||||
<uui-icon name="icon-remove"></uui-icon>${this.localize.term('general_cancel')}
|
||||
</uui-button>
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
#handleBrowse(e: Event) {
|
||||
if (!this._dropzone) return;
|
||||
e.stopImmediatePropagation();
|
||||
this._dropzone.browse();
|
||||
}
|
||||
|
||||
#handleCancel(item: UmbUploadableItem) {
|
||||
item.temporaryFile?.abortController?.abort();
|
||||
}
|
||||
|
||||
#handleRemove() {
|
||||
this.#manager.removeAll();
|
||||
}
|
||||
|
||||
async #onUpload(e: UUIFileDropzoneEvent) {
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
if (this.disabled) return;
|
||||
if (!e.detail.files.length && !e.detail.folders.length) return;
|
||||
|
||||
if (this.createAsTemporary) {
|
||||
const uploadables = this.#manager.createTemporaryFiles(e.detail.files);
|
||||
this.dispatchEvent(new UmbDropzoneSubmittedEvent(await uploadables));
|
||||
} else {
|
||||
const uploadables = this.#manager.createMediaItems(e.detail, null);
|
||||
this.dispatchEvent(new UmbDropzoneSubmittedEvent(uploadables));
|
||||
}
|
||||
}
|
||||
|
||||
static override readonly styles = [
|
||||
UmbTextStyles,
|
||||
css`
|
||||
:host([disabled]) #dropzone {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#dropzone {
|
||||
inset: 0;
|
||||
backdrop-filter: opacity(1); /* Removes the built in blur effect */
|
||||
overflow: clip;
|
||||
}
|
||||
|
||||
#uploader {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: var(--uui-size-space-3);
|
||||
|
||||
.placeholder {
|
||||
display: grid;
|
||||
grid-template-columns: 30px 200px 1fr;
|
||||
max-width: fit-content;
|
||||
padding: var(--uui-size-space-3);
|
||||
border: 1px dashed var(--uui-color-divider-emphasis);
|
||||
}
|
||||
|
||||
.fileIcon,
|
||||
.fileActions {
|
||||
place-self: center center;
|
||||
}
|
||||
|
||||
.fileName {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: var(--uui-size-5);
|
||||
}
|
||||
|
||||
.fileSize {
|
||||
font-size: var(--uui-font-size-small);
|
||||
color: var(--uui-color-text-alt);
|
||||
}
|
||||
|
||||
.error {
|
||||
color: var(--uui-color-danger);
|
||||
}
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
export const UmbInputDropzoneDashedStyles = css`
|
||||
umb-input-dropzone {
|
||||
position: relative;
|
||||
display: block;
|
||||
inset: 0;
|
||||
cursor: pointer;
|
||||
border: 1px dashed var(--uui-color-divider-emphasis);
|
||||
}
|
||||
`;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-input-dropzone': UmbInputDropzoneElement;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import type { UmbInputDropzoneElement } from './input-dropzone.element.js';
|
||||
import type { Meta, StoryObj } from '@storybook/web-components';
|
||||
import { html } from '@umbraco-cms/backoffice/external/lit';
|
||||
|
||||
import './input-dropzone.element.js';
|
||||
|
||||
const meta: Meta<UmbInputDropzoneElement> = {
|
||||
id: 'umb-input-dropzone',
|
||||
title: 'Components/Inputs/Dropzone',
|
||||
component: 'umb-input-dropzone',
|
||||
args: {
|
||||
disabled: false,
|
||||
accept: '',
|
||||
createAsTemporary: true,
|
||||
},
|
||||
decorators: [(Story) => html`<div style="width: 300px">${Story()}</div>`],
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
actions: {
|
||||
handles: ['submitted', 'change'],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<UmbInputDropzoneElement>;
|
||||
|
||||
export const Overview: Story = {};
|
||||
|
||||
export const WithDisabled: Story = {
|
||||
args: {
|
||||
disabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithAccept: Story = {
|
||||
args: {
|
||||
accept: 'jpg,png',
|
||||
},
|
||||
parameters: {
|
||||
docs: {
|
||||
description: {
|
||||
story: 'This is a dropzone with an accept attribute set to "jpg,png".',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const WithDefaultSlot: Story = {
|
||||
render: () =>
|
||||
html`<umb-input-dropzone>
|
||||
<div>Custom slot</div>
|
||||
</umb-input-dropzone>`,
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
export { UMB_DROPZONE_MEDIA_TYPE_PICKER_MODAL } from './modals/dropzone-media-type-picker/dropzone-media-type-picker-modal.token.js';
|
||||
|
||||
export enum UmbFileDropzoneItemStatus {
|
||||
WAITING = 'waiting',
|
||||
COMPLETE = 'complete',
|
||||
NOT_ALLOWED = 'not allowed',
|
||||
CANCELLED = 'cancelled',
|
||||
ERROR = 'error',
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import type { UmbUploadableItem } from './types.js';
|
||||
|
||||
export class UmbDropzoneChangeEvent extends Event {
|
||||
public static readonly TYPE = 'change';
|
||||
|
||||
/**
|
||||
* An array of resolved uploadable items.
|
||||
*/
|
||||
public items;
|
||||
|
||||
public constructor(items: Array<UmbUploadableItem>, args?: EventInit) {
|
||||
super(UmbDropzoneChangeEvent.TYPE, { bubbles: false, composed: false, cancelable: false, ...args });
|
||||
this.items = items;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbMediaDetailRepository } from '../repository/index.js';
|
||||
import type { UmbMediaDetailModel, UmbMediaValueModel } from '../types.js';
|
||||
import { UmbFileDropzoneItemStatus } from './types.js';
|
||||
import { UmbMediaDetailRepository } from '../media/repository/index.js';
|
||||
import type { UmbMediaDetailModel, UmbMediaValueModel } from '../media/types.js';
|
||||
import { UmbFileDropzoneItemStatus } from './constants.js';
|
||||
import { UMB_DROPZONE_MEDIA_TYPE_PICKER_MODAL } from './modals/index.js';
|
||||
import type {
|
||||
UmbUploadableFile,
|
||||
@@ -11,7 +11,11 @@ import type {
|
||||
UmbAllowedMediaTypesOfExtension,
|
||||
UmbAllowedChildrenOfMediaType,
|
||||
} from './types.js';
|
||||
import { TemporaryFileStatus, UmbTemporaryFileManager } from '@umbraco-cms/backoffice/temporary-file';
|
||||
import {
|
||||
TemporaryFileStatus,
|
||||
UmbTemporaryFileManager,
|
||||
type UmbTemporaryFileModel,
|
||||
} from '@umbraco-cms/backoffice/temporary-file';
|
||||
import { UmbArrayState, UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
|
||||
import { UmbId } from '@umbraco-cms/backoffice/id';
|
||||
@@ -111,11 +115,7 @@ export class UmbDropzoneManager extends UmbControllerBase {
|
||||
|
||||
for (const item of uploadableItems) {
|
||||
// Upload as temp file
|
||||
const uploaded = await this.#tempFileManager.uploadOne({
|
||||
temporaryUnique: item.temporaryFile.temporaryUnique,
|
||||
file: item.temporaryFile.file,
|
||||
onProgress: (progress) => this.#updateProgress(item, progress),
|
||||
});
|
||||
const uploaded = await this.#tempFileManager.uploadOne(item.temporaryFile);
|
||||
|
||||
// Update progress
|
||||
if (uploaded.status === TemporaryFileStatus.SUCCESS) {
|
||||
@@ -131,6 +131,35 @@ export class UmbDropzoneManager extends UmbControllerBase {
|
||||
return uploadedItems;
|
||||
}
|
||||
|
||||
public removeOne(item: UmbUploadableItem) {
|
||||
item.temporaryFile?.abortController?.abort();
|
||||
this.#progressItems.removeOne(item.unique);
|
||||
if (item.temporaryFile) {
|
||||
this.#tempFileManager.removeOne(item.temporaryFile.temporaryUnique);
|
||||
}
|
||||
}
|
||||
|
||||
public remove(items: Array<UmbUploadableItem>) {
|
||||
const uniques: string[] = [];
|
||||
for (const item of items) {
|
||||
item.temporaryFile?.abortController?.abort();
|
||||
if (item.temporaryFile) {
|
||||
uniques.push(item.temporaryFile.temporaryUnique);
|
||||
}
|
||||
}
|
||||
this.#progressItems.remove(uniques);
|
||||
const temporaryUniques = items.map((x) => x.temporaryFile?.temporaryUnique).filter((x): x is string => !!x);
|
||||
this.#tempFileManager.remove(temporaryUniques);
|
||||
}
|
||||
|
||||
public removeAll() {
|
||||
for (const item of this.#progressItems.getValue()) {
|
||||
item.temporaryFile?.abortController?.abort();
|
||||
}
|
||||
this.#progressItems.setValue([]);
|
||||
this.#tempFileManager.removeAll();
|
||||
}
|
||||
|
||||
async #showDialogMediaTypePicker(options: Array<UmbAllowedMediaTypeModel>) {
|
||||
const modalManager = await this.getContext(UMB_MODAL_MANAGER_CONTEXT);
|
||||
const modalContext = modalManager.open(this.#host, UMB_DROPZONE_MEDIA_TYPE_PICKER_MODAL, { data: { options } });
|
||||
@@ -188,6 +217,10 @@ export class UmbDropzoneManager extends UmbControllerBase {
|
||||
async #handleFile(item: UmbUploadableFile, mediaTypeUnique: string) {
|
||||
// Upload the file as a temporary file and update progress.
|
||||
const temporaryFile = await this.#uploadAsTemporaryFile(item);
|
||||
if (temporaryFile.status === TemporaryFileStatus.CANCELLED) {
|
||||
this.#updateStatus(item, UmbFileDropzoneItemStatus.CANCELLED);
|
||||
return;
|
||||
}
|
||||
if (temporaryFile.status !== TemporaryFileStatus.SUCCESS) {
|
||||
this.#updateStatus(item, UmbFileDropzoneItemStatus.ERROR);
|
||||
return;
|
||||
@@ -215,11 +248,7 @@ export class UmbDropzoneManager extends UmbControllerBase {
|
||||
}
|
||||
|
||||
#uploadAsTemporaryFile(item: UmbUploadableFile) {
|
||||
return this.#tempFileManager.uploadOne({
|
||||
temporaryUnique: item.temporaryFile.temporaryUnique,
|
||||
file: item.temporaryFile.file,
|
||||
onProgress: (progress) => this.#updateProgress(item, progress),
|
||||
});
|
||||
return this.#tempFileManager.uploadOne(item.temporaryFile);
|
||||
}
|
||||
|
||||
// Media types
|
||||
@@ -322,13 +351,26 @@ export class UmbDropzoneManager extends UmbControllerBase {
|
||||
const items: Array<UmbUploadableItem> = [];
|
||||
|
||||
for (const file of files) {
|
||||
items.push({
|
||||
const temporaryFile: UmbTemporaryFileModel = {
|
||||
file,
|
||||
temporaryUnique: UmbId.new(),
|
||||
abortController: new AbortController(),
|
||||
onProgress: (progress) => this.#updateProgress(uploadableItem, progress),
|
||||
};
|
||||
|
||||
const uploadableItem: UmbUploadableFile = {
|
||||
unique: UmbId.new(),
|
||||
parentUnique,
|
||||
status: UmbFileDropzoneItemStatus.WAITING,
|
||||
progress: 0,
|
||||
temporaryFile: { file, temporaryUnique: UmbId.new() },
|
||||
temporaryFile,
|
||||
};
|
||||
|
||||
temporaryFile.abortController?.signal.addEventListener('abort', () => {
|
||||
this.#updateStatus(uploadableItem, UmbFileDropzoneItemStatus.CANCELLED);
|
||||
});
|
||||
|
||||
items.push(uploadableItem);
|
||||
}
|
||||
|
||||
for (const subfolder of folders) {
|
||||
@@ -0,0 +1,7 @@
|
||||
export * from './constants.js';
|
||||
export * from './components/index.js';
|
||||
export * from './modals/index.js';
|
||||
export * from './dropzone-manager.class.js';
|
||||
export * from './dropzone-submitted.event.js';
|
||||
export * from './dropzone-change.event.js';
|
||||
export type * from './types.js';
|
||||
@@ -0,0 +1,3 @@
|
||||
import { manifests as modalManifests } from './modals/manifests.js';
|
||||
|
||||
export const manifests: Array<UmbExtensionManifest> = [...modalManifests];
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { UmbFileDropzoneItemStatus } from './constants.js';
|
||||
import type { UUIFileFolder } from '@umbraco-cms/backoffice/external/uui';
|
||||
import type { UmbAllowedMediaTypeModel } from '@umbraco-cms/backoffice/media-type';
|
||||
import type { UmbTemporaryFileModel } from '@umbraco-cms/backoffice/temporary-file';
|
||||
@@ -38,11 +39,3 @@ export interface UmbFileDropzoneProgress {
|
||||
total: number;
|
||||
completed: number;
|
||||
}
|
||||
|
||||
export enum UmbFileDropzoneItemStatus {
|
||||
WAITING = 'waiting',
|
||||
COMPLETE = 'complete',
|
||||
NOT_ALLOWED = 'not allowed',
|
||||
CANCELLED = 'cancelled',
|
||||
ERROR = 'error',
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { manifests as mediaManifests } from './media/manifests.js';
|
||||
import { manifests as mediaSectionManifests } from './media-section/manifests.js';
|
||||
import { manifests as mediaTypesManifests } from './media-types/manifests.js';
|
||||
import { manifests as imagingManifests } from './imaging/manifests.js';
|
||||
import { manifests as dropzoneManifests } from './dropzone/manifests.js';
|
||||
import type { UmbExtensionManifestKind } from '@umbraco-cms/backoffice/extension-registry';
|
||||
|
||||
export const manifests: Array<UmbExtensionManifest | UmbExtensionManifestKind> = [
|
||||
@@ -9,4 +10,5 @@ export const manifests: Array<UmbExtensionManifest | UmbExtensionManifestKind> =
|
||||
...mediaManifests,
|
||||
...mediaTypesManifests,
|
||||
...imagingManifests,
|
||||
...dropzoneManifests,
|
||||
];
|
||||
|
||||
@@ -125,15 +125,19 @@ export class UmbMediaTypeImportModalLayout extends UmbModalBaseElement<
|
||||
label=${this.localize.term('general_remove')}></uui-button>
|
||||
</uui-ref-node>`,
|
||||
() =>
|
||||
/**TODO Add localizations */
|
||||
html`<div id="wrapper">
|
||||
Drag and drop your file here
|
||||
<uui-button look="primary" label="or click here to choose a file" @click=${this.#onBrowse}></uui-button>
|
||||
<umb-localize key="media_dragAndDropYourFilesIntoTheArea"
|
||||
>Drag and drop your file(s) into the area
|
||||
</umb-localize>
|
||||
<uui-button
|
||||
look="primary"
|
||||
label="${this.localize.term('media_clickToUpload')}"
|
||||
@click=${this.#onBrowse}></uui-button>
|
||||
<umb-dropzone
|
||||
id="dropzone"
|
||||
accept=".udt"
|
||||
@complete=${this.#onUploadCompleted}
|
||||
createAsTemporary></umb-dropzone>
|
||||
create-as-temporary
|
||||
@complete=${this.#onUploadCompleted}></umb-dropzone>
|
||||
</div>`,
|
||||
)}
|
||||
`;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { UMB_MEDIA_PLACEHOLDER_ENTITY_TYPE } from '../entity.js';
|
||||
import type { UmbFileDropzoneItemStatus } from '../dropzone/types.js';
|
||||
import { UMB_MEDIA_GRID_COLLECTION_VIEW_ALIAS } from './views/constants.js';
|
||||
import type { UmbMediaCollectionFilterModel, UmbMediaCollectionItemModel } from './types.js';
|
||||
import type { UmbFileDropzoneItemStatus } from '@umbraco-cms/backoffice/dropzone';
|
||||
import { UmbDefaultCollectionContext } from '@umbraco-cms/backoffice/collection';
|
||||
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api';
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { UMB_MEDIA_ENTITY_TYPE, UMB_MEDIA_ROOT_ENTITY_TYPE } from '../entity.js';
|
||||
import { UMB_MEDIA_WORKSPACE_CONTEXT } from '../workspace/media-workspace.context-token.js';
|
||||
import type { UmbDropzoneSubmittedEvent } from '../dropzone/dropzone-submitted.event.js';
|
||||
import type { UmbDropzoneElement } from '../dropzone/dropzone.element.js';
|
||||
import { UMB_MEDIA_COLLECTION_CONTEXT } from './media-collection.context-token.js';
|
||||
import { customElement, html, ref, state, when } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbCollectionDefaultElement } from '@umbraco-cms/backoffice/collection';
|
||||
import { UmbRequestReloadChildrenOfEntityEvent } from '@umbraco-cms/backoffice/entity-action';
|
||||
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
|
||||
import type { UmbDropzoneElement, UmbDropzoneSubmittedEvent } from '@umbraco-cms/backoffice/dropzone';
|
||||
|
||||
@customElement('umb-media-collection')
|
||||
export class UmbMediaCollectionElement extends UmbCollectionDefaultElement {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { UmbFileDropzoneItemStatus } from '../dropzone/types.js';
|
||||
import type { UmbFileDropzoneItemStatus } from '@umbraco-cms/backoffice/dropzone';
|
||||
import type { UmbCollectionFilterModel } from '@umbraco-cms/backoffice/collection';
|
||||
|
||||
export interface UmbMediaCollectionFilterModel extends UmbCollectionFilterModel {
|
||||
|
||||
@@ -2,11 +2,11 @@ import { UMB_EDIT_MEDIA_WORKSPACE_PATH_PATTERN } from '../../../paths.js';
|
||||
import type { UmbMediaCollectionItemModel } from '../../types.js';
|
||||
import type { UmbMediaCollectionContext } from '../../media-collection.context.js';
|
||||
import { UMB_MEDIA_COLLECTION_CONTEXT } from '../../media-collection.context-token.js';
|
||||
import { UmbFileDropzoneItemStatus } from '../../../dropzone/types.js';
|
||||
import { UMB_MEDIA_PLACEHOLDER_ENTITY_TYPE } from '../../../entity.js';
|
||||
import { css, customElement, html, ifDefined, repeat, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import { UmbFileDropzoneItemStatus } from '@umbraco-cms/backoffice/dropzone';
|
||||
|
||||
import '@umbraco-cms/backoffice/imaging';
|
||||
import type { UmbModalRouteBuilder } from '@umbraco-cms/backoffice/router';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UMB_IMAGE_CROPPER_EDITOR_MODAL, UMB_MEDIA_PICKER_MODAL } from '../../modals/index.js';
|
||||
import type { UmbMediaItemModel, UmbCropModel, UmbMediaPickerPropertyValueEntry } from '../../types.js';
|
||||
import type { UmbUploadableItem } from '../../dropzone/types.js';
|
||||
import type { UmbUploadableItem } from '@umbraco-cms/backoffice/dropzone';
|
||||
import { css, customElement, html, nothing, property, repeat, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { umbConfirmModal, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal';
|
||||
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
|
||||
|
||||
@@ -69,8 +69,6 @@ export class UmbInputUploadFieldElement extends UmbLitElement {
|
||||
|
||||
#manifests: Array<ManifestFileUploadPreview> = [];
|
||||
|
||||
#uploadAbort?: AbortController;
|
||||
|
||||
override updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>) {
|
||||
super.updated(changedProperties);
|
||||
|
||||
@@ -154,22 +152,19 @@ export class UmbInputUploadFieldElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
async #onUpload(e: UUIFileDropzoneEvent) {
|
||||
//Property Editor for Upload field will always only have one file.
|
||||
this.temporaryFile = {
|
||||
temporaryUnique: UmbId.new(),
|
||||
status: TemporaryFileStatus.WAITING,
|
||||
file: e.detail.files[0],
|
||||
};
|
||||
|
||||
try {
|
||||
this.#uploadAbort = new AbortController();
|
||||
const uploaded = await this.#manager.uploadOne({
|
||||
...this.temporaryFile,
|
||||
//Property Editor for Upload field will always only have one file.
|
||||
this.temporaryFile = {
|
||||
temporaryUnique: UmbId.new(),
|
||||
status: TemporaryFileStatus.WAITING,
|
||||
file: e.detail.files[0],
|
||||
onProgress: (p) => {
|
||||
this._progress = Math.ceil(p);
|
||||
},
|
||||
abortSignal: this.#uploadAbort.signal,
|
||||
});
|
||||
abortController: new AbortController(),
|
||||
};
|
||||
|
||||
const uploaded = await this.#manager.uploadOne(this.temporaryFile);
|
||||
|
||||
if (uploaded.status === TemporaryFileStatus.SUCCESS) {
|
||||
this.temporaryFile.status = TemporaryFileStatus.SUCCESS;
|
||||
@@ -190,8 +185,6 @@ export class UmbInputUploadFieldElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
// If the error was caused by the upload being aborted, do not show an error message.
|
||||
} finally {
|
||||
this.#uploadAbort = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,13 +285,13 @@ export class UmbInputUploadFieldElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
#handleRemove() {
|
||||
// If the upload promise happens to be in progress, cancel it.
|
||||
this.temporaryFile?.abortController?.abort();
|
||||
|
||||
this.value = { src: undefined };
|
||||
this.temporaryFile = undefined;
|
||||
this._progress = 0;
|
||||
this.dispatchEvent(new UmbChangeEvent());
|
||||
|
||||
// If the upload promise happens to be in progress, cancel it.
|
||||
this.#uploadAbort?.abort();
|
||||
}
|
||||
|
||||
static override readonly styles = [
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
export * from './collection/constants.js';
|
||||
export * from './dropzone/constants.js';
|
||||
export * from './entity-actions/constants.js';
|
||||
export * from './entity-bulk-actions/constants.js';
|
||||
export * from './menu/constants.js';
|
||||
@@ -11,7 +10,6 @@ export * from './search/constants.js';
|
||||
export * from './tree/constants.js';
|
||||
export * from './url/constants.js';
|
||||
export * from './workspace/constants.js';
|
||||
|
||||
export * from './paths.js';
|
||||
|
||||
export { UMB_MEDIA_VARIANT_CONTEXT } from './property-dataset-context/media-property-dataset-context.token.js';
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { UMB_DROPZONE_MEDIA_TYPE_PICKER_MODAL } from './modals/dropzone-media-type-picker/dropzone-media-type-picker-modal.token.js';
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from './dropzone.element.js';
|
||||
export * from './dropzone-manager.class.js';
|
||||
export * from './dropzone-submitted.event.js';
|
||||
@@ -1 +0,0 @@
|
||||
export * from './modals/manifests.js';
|
||||
@@ -1,6 +1,5 @@
|
||||
export * from './components/index.js';
|
||||
export * from './constants.js';
|
||||
export * from './dropzone/index.js';
|
||||
export * from './reference/index.js';
|
||||
export * from './repository/index.js';
|
||||
export * from './search/index.js';
|
||||
@@ -10,3 +9,8 @@ export * from './utils/index.js';
|
||||
export { UmbMediaAuditLogRepository } from './audit-log/index.js';
|
||||
|
||||
export type * from './types.js';
|
||||
|
||||
/**
|
||||
* @deprecated Please import directly from the `@umbraco-cms/backoffice/dropzone` package instead. This package will be removed in Umbraco 18.
|
||||
*/
|
||||
export * from '@umbraco-cms/backoffice/dropzone';
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { manifests as auditLogManifests } from './audit-log/manifests.js';
|
||||
import { manifests as collectionManifests } from './collection/manifests.js';
|
||||
import { manifests as dropzoneManifests } from './dropzone/manifests.js';
|
||||
import { manifests as entityActionsManifests } from './entity-actions/manifests.js';
|
||||
import { manifests as entityBulkActionsManifests } from './entity-bulk-actions/manifests.js';
|
||||
import { manifests as fileUploadPreviewManifests } from './components/input-upload-field/manifests.js';
|
||||
@@ -20,7 +19,6 @@ import { manifests as workspaceManifests } from './workspace/manifests.js';
|
||||
export const manifests: Array<UmbExtensionManifest> = [
|
||||
...auditLogManifests,
|
||||
...collectionManifests,
|
||||
...dropzoneManifests,
|
||||
...entityActionsManifests,
|
||||
...entityBulkActionsManifests,
|
||||
...fileUploadPreviewManifests,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { UmbMediaItemRepository } from '../../repository/index.js';
|
||||
import { UmbMediaTreeRepository } from '../../tree/media-tree.repository.js';
|
||||
import { UMB_MEDIA_ROOT_ENTITY_TYPE } from '../../entity.js';
|
||||
import type { UmbDropzoneElement } from '../../dropzone/dropzone.element.js';
|
||||
import type { UmbMediaTreeItemModel, UmbMediaSearchItemModel, UmbMediaItemModel } from '../../types.js';
|
||||
import { UmbMediaSearchProvider } from '../../search/index.js';
|
||||
import type { UmbMediaPathModel } 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 type { UmbDropzoneElement } from '@umbraco-cms/backoffice/dropzone';
|
||||
import {
|
||||
css,
|
||||
html,
|
||||
|
||||
@@ -5,7 +5,6 @@ import type { UmbContentDetailModel, UmbElementValueModel } from '@umbraco-cms/b
|
||||
|
||||
export type * from './audit-log/types.js';
|
||||
export type * from './collection/types.js';
|
||||
export type * from './dropzone/types.js';
|
||||
export type * from './modals/types.js';
|
||||
export type * from './recycle-bin/types.js';
|
||||
export type * from './repository/types.js';
|
||||
|
||||
@@ -13,6 +13,7 @@ export default defineConfig({
|
||||
entry: {
|
||||
'entry-point': 'entry-point.ts',
|
||||
'imaging/index': 'imaging/index.ts',
|
||||
'dropzone/index': 'dropzone/index.ts',
|
||||
'media-types/index': 'media-types/index.ts',
|
||||
'media/index': 'media/index.ts',
|
||||
'umbraco-package': 'umbraco-package.ts',
|
||||
|
||||
@@ -68,6 +68,7 @@ DON'T EDIT THIS FILE DIRECTLY. It is generated by /devops/tsconfig/index.js
|
||||
"@umbraco-cms/backoffice/document-blueprint": ["./src/packages/documents/document-blueprints/index.ts"],
|
||||
"@umbraco-cms/backoffice/document-type": ["./src/packages/documents/document-types/index.ts"],
|
||||
"@umbraco-cms/backoffice/document": ["./src/packages/documents/documents/index.ts"],
|
||||
"@umbraco-cms/backoffice/dropzone": ["./src/packages/media/dropzone/index.ts"],
|
||||
"@umbraco-cms/backoffice/entity-action": ["./src/packages/core/entity-action/index.ts"],
|
||||
"@umbraco-cms/backoffice/entity-bulk-action": ["./src/packages/core/entity-bulk-action/index.ts"],
|
||||
"@umbraco-cms/backoffice/entity-create-option-action": [
|
||||
|
||||
@@ -1,530 +0,0 @@
|
||||
|
||||
import * as import0 from '@umbraco-cms/backoffice/app';
|
||||
import * as import1 from '@umbraco-cms/backoffice/class-api';
|
||||
import * as import2 from '@umbraco-cms/backoffice/context-api';
|
||||
import * as import3 from '@umbraco-cms/backoffice/controller-api';
|
||||
import * as import4 from '@umbraco-cms/backoffice/element-api';
|
||||
import * as import5 from '@umbraco-cms/backoffice/embedded-media';
|
||||
import * as import6 from '@umbraco-cms/backoffice/extension-api';
|
||||
import * as import7 from '@umbraco-cms/backoffice/formatting-api';
|
||||
import * as import8 from '@umbraco-cms/backoffice/localization-api';
|
||||
import * as import9 from '@umbraco-cms/backoffice/observable-api';
|
||||
import * as import10 from '@umbraco-cms/backoffice/action';
|
||||
import * as import11 from '@umbraco-cms/backoffice/audit-log';
|
||||
import * as import12 from '@umbraco-cms/backoffice/auth';
|
||||
import * as import13 from '@umbraco-cms/backoffice/block-custom-view';
|
||||
import * as import14 from '@umbraco-cms/backoffice/block-grid';
|
||||
import * as import15 from '@umbraco-cms/backoffice/block-list';
|
||||
import * as import16 from '@umbraco-cms/backoffice/block-rte';
|
||||
import * as import17 from '@umbraco-cms/backoffice/block-type';
|
||||
import * as import18 from '@umbraco-cms/backoffice/block';
|
||||
import * as import19 from '@umbraco-cms/backoffice/clipboard';
|
||||
import * as import20 from '@umbraco-cms/backoffice/code-editor';
|
||||
import * as import21 from '@umbraco-cms/backoffice/collection';
|
||||
import * as import22 from '@umbraco-cms/backoffice/components';
|
||||
import * as import23 from '@umbraco-cms/backoffice/const';
|
||||
import * as import24 from '@umbraco-cms/backoffice/content-type';
|
||||
import * as import25 from '@umbraco-cms/backoffice/content';
|
||||
import * as import26 from '@umbraco-cms/backoffice/culture';
|
||||
import * as import27 from '@umbraco-cms/backoffice/current-user';
|
||||
import * as import28 from '@umbraco-cms/backoffice/dashboard';
|
||||
import * as import29 from '@umbraco-cms/backoffice/data-type';
|
||||
import * as import30 from '@umbraco-cms/backoffice/debug';
|
||||
import * as import31 from '@umbraco-cms/backoffice/dictionary';
|
||||
import * as import32 from '@umbraco-cms/backoffice/document-blueprint';
|
||||
import * as import33 from '@umbraco-cms/backoffice/document-type';
|
||||
import * as import34 from '@umbraco-cms/backoffice/document';
|
||||
import * as import35 from '@umbraco-cms/backoffice/entity-action';
|
||||
import * as import36 from '@umbraco-cms/backoffice/entity-bulk-action';
|
||||
import * as import37 from '@umbraco-cms/backoffice/entity-create-option-action';
|
||||
import * as import38 from '@umbraco-cms/backoffice/entity';
|
||||
import * as import39 from '@umbraco-cms/backoffice/entity-item';
|
||||
import * as import40 from '@umbraco-cms/backoffice/event';
|
||||
import * as import41 from '@umbraco-cms/backoffice/extension-registry';
|
||||
import * as import42 from '@umbraco-cms/backoffice/health-check';
|
||||
import * as import43 from '@umbraco-cms/backoffice/help';
|
||||
import * as import44 from '@umbraco-cms/backoffice/icon';
|
||||
import * as import45 from '@umbraco-cms/backoffice/id';
|
||||
import * as import46 from '@umbraco-cms/backoffice/imaging';
|
||||
import * as import47 from '@umbraco-cms/backoffice/language';
|
||||
import * as import48 from '@umbraco-cms/backoffice/lit-element';
|
||||
import * as import49 from '@umbraco-cms/backoffice/localization';
|
||||
import * as import50 from '@umbraco-cms/backoffice/log-viewer';
|
||||
import * as import51 from '@umbraco-cms/backoffice/media-type';
|
||||
import * as import52 from '@umbraco-cms/backoffice/media';
|
||||
import * as import53 from '@umbraco-cms/backoffice/member-group';
|
||||
import * as import54 from '@umbraco-cms/backoffice/member-type';
|
||||
import * as import55 from '@umbraco-cms/backoffice/member';
|
||||
import * as import56 from '@umbraco-cms/backoffice/menu';
|
||||
import * as import57 from '@umbraco-cms/backoffice/modal';
|
||||
import * as import58 from '@umbraco-cms/backoffice/multi-url-picker';
|
||||
import * as import59 from '@umbraco-cms/backoffice/notification';
|
||||
import * as import60 from '@umbraco-cms/backoffice/object-type';
|
||||
import * as import61 from '@umbraco-cms/backoffice/package';
|
||||
import * as import62 from '@umbraco-cms/backoffice/partial-view';
|
||||
import * as import63 from '@umbraco-cms/backoffice/picker-input';
|
||||
import * as import64 from '@umbraco-cms/backoffice/picker';
|
||||
import * as import65 from '@umbraco-cms/backoffice/property-action';
|
||||
import * as import66 from '@umbraco-cms/backoffice/property-editor';
|
||||
import * as import67 from '@umbraco-cms/backoffice/property-type';
|
||||
import * as import68 from '@umbraco-cms/backoffice/property';
|
||||
import * as import69 from '@umbraco-cms/backoffice/recycle-bin';
|
||||
import * as import70 from '@umbraco-cms/backoffice/relation-type';
|
||||
import * as import71 from '@umbraco-cms/backoffice/relations';
|
||||
import * as import72 from '@umbraco-cms/backoffice/repository';
|
||||
import * as import73 from '@umbraco-cms/backoffice/resources';
|
||||
import * as import74 from '@umbraco-cms/backoffice/router';
|
||||
import * as import75 from '@umbraco-cms/backoffice/rte';
|
||||
import * as import76 from '@umbraco-cms/backoffice/script';
|
||||
import * as import77 from '@umbraco-cms/backoffice/search';
|
||||
import * as import78 from '@umbraco-cms/backoffice/section';
|
||||
import * as import79 from '@umbraco-cms/backoffice/server-file-system';
|
||||
import * as import80 from '@umbraco-cms/backoffice/settings';
|
||||
import * as import81 from '@umbraco-cms/backoffice/sorter';
|
||||
import * as import82 from '@umbraco-cms/backoffice/static-file';
|
||||
import * as import83 from '@umbraco-cms/backoffice/store';
|
||||
import * as import84 from '@umbraco-cms/backoffice/style';
|
||||
import * as import85 from '@umbraco-cms/backoffice/stylesheet';
|
||||
import * as import86 from '@umbraco-cms/backoffice/sysinfo';
|
||||
import * as import87 from '@umbraco-cms/backoffice/tags';
|
||||
import * as import88 from '@umbraco-cms/backoffice/template';
|
||||
import * as import89 from '@umbraco-cms/backoffice/temporary-file';
|
||||
import * as import90 from '@umbraco-cms/backoffice/themes';
|
||||
import * as import91 from '@umbraco-cms/backoffice/tiny-mce';
|
||||
import * as import92 from '@umbraco-cms/backoffice/tiptap';
|
||||
import * as import93 from '@umbraco-cms/backoffice/translation';
|
||||
import * as import94 from '@umbraco-cms/backoffice/tree';
|
||||
import * as import95 from '@umbraco-cms/backoffice/ufm';
|
||||
import * as import96 from '@umbraco-cms/backoffice/user-change-password';
|
||||
import * as import97 from '@umbraco-cms/backoffice/user-group';
|
||||
import * as import98 from '@umbraco-cms/backoffice/user-permission';
|
||||
import * as import99 from '@umbraco-cms/backoffice/user';
|
||||
import * as import100 from '@umbraco-cms/backoffice/utils';
|
||||
import * as import101 from '@umbraco-cms/backoffice/validation';
|
||||
import * as import102 from '@umbraco-cms/backoffice/variant';
|
||||
import * as import103 from '@umbraco-cms/backoffice/webhook';
|
||||
import * as import104 from '@umbraco-cms/backoffice/workspace';
|
||||
|
||||
export const imports = [
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/app',
|
||||
package: import0
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/class-api',
|
||||
package: import1
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/context-api',
|
||||
package: import2
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/controller-api',
|
||||
package: import3
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/element-api',
|
||||
package: import4
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/embedded-media',
|
||||
package: import5
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/extension-api',
|
||||
package: import6
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/formatting-api',
|
||||
package: import7
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/localization-api',
|
||||
package: import8
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/observable-api',
|
||||
package: import9
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/action',
|
||||
package: import10
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/audit-log',
|
||||
package: import11
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/auth',
|
||||
package: import12
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/block-custom-view',
|
||||
package: import13
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/block-grid',
|
||||
package: import14
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/block-list',
|
||||
package: import15
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/block-rte',
|
||||
package: import16
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/block-type',
|
||||
package: import17
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/block',
|
||||
package: import18
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/clipboard',
|
||||
package: import19
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/code-editor',
|
||||
package: import20
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/collection',
|
||||
package: import21
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/components',
|
||||
package: import22
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/const',
|
||||
package: import23
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/content-type',
|
||||
package: import24
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/content',
|
||||
package: import25
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/culture',
|
||||
package: import26
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/current-user',
|
||||
package: import27
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/dashboard',
|
||||
package: import28
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/data-type',
|
||||
package: import29
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/debug',
|
||||
package: import30
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/dictionary',
|
||||
package: import31
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/document-blueprint',
|
||||
package: import32
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/document-type',
|
||||
package: import33
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/document',
|
||||
package: import34
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/entity-action',
|
||||
package: import35
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/entity-bulk-action',
|
||||
package: import36
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/entity-create-option-action',
|
||||
package: import37
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/entity',
|
||||
package: import38
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/entity-item',
|
||||
package: import39
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/event',
|
||||
package: import40
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/extension-registry',
|
||||
package: import41
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/health-check',
|
||||
package: import42
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/help',
|
||||
package: import43
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/icon',
|
||||
package: import44
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/id',
|
||||
package: import45
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/imaging',
|
||||
package: import46
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/language',
|
||||
package: import47
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/lit-element',
|
||||
package: import48
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/localization',
|
||||
package: import49
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/log-viewer',
|
||||
package: import50
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/media-type',
|
||||
package: import51
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/media',
|
||||
package: import52
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/member-group',
|
||||
package: import53
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/member-type',
|
||||
package: import54
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/member',
|
||||
package: import55
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/menu',
|
||||
package: import56
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/modal',
|
||||
package: import57
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/multi-url-picker',
|
||||
package: import58
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/notification',
|
||||
package: import59
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/object-type',
|
||||
package: import60
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/package',
|
||||
package: import61
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/partial-view',
|
||||
package: import62
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/picker-input',
|
||||
package: import63
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/picker',
|
||||
package: import64
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/property-action',
|
||||
package: import65
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/property-editor',
|
||||
package: import66
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/property-type',
|
||||
package: import67
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/property',
|
||||
package: import68
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/recycle-bin',
|
||||
package: import69
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/relation-type',
|
||||
package: import70
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/relations',
|
||||
package: import71
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/repository',
|
||||
package: import72
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/resources',
|
||||
package: import73
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/router',
|
||||
package: import74
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/rte',
|
||||
package: import75
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/script',
|
||||
package: import76
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/search',
|
||||
package: import77
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/section',
|
||||
package: import78
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/server-file-system',
|
||||
package: import79
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/settings',
|
||||
package: import80
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/sorter',
|
||||
package: import81
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/static-file',
|
||||
package: import82
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/store',
|
||||
package: import83
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/style',
|
||||
package: import84
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/stylesheet',
|
||||
package: import85
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/sysinfo',
|
||||
package: import86
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/tags',
|
||||
package: import87
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/template',
|
||||
package: import88
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/temporary-file',
|
||||
package: import89
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/themes',
|
||||
package: import90
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/tiny-mce',
|
||||
package: import91
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/tiptap',
|
||||
package: import92
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/translation',
|
||||
package: import93
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/tree',
|
||||
package: import94
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/ufm',
|
||||
package: import95
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/user-change-password',
|
||||
package: import96
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/user-group',
|
||||
package: import97
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/user-permission',
|
||||
package: import98
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/user',
|
||||
package: import99
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/utils',
|
||||
package: import100
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/validation',
|
||||
package: import101
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/variant',
|
||||
package: import102
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/webhook',
|
||||
package: import103
|
||||
},
|
||||
{
|
||||
path: '@umbraco-cms/backoffice/workspace',
|
||||
package: import104
|
||||
}
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user