diff --git a/.vscode/lit.code-snippets b/.vscode/lit.code-snippets new file mode 120000 index 0000000000..aa55c3049d --- /dev/null +++ b/.vscode/lit.code-snippets @@ -0,0 +1 @@ +../src/Umbraco.Web.UI.Client/.vscode/lit.code-snippets \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/.vscode/lit.code-snippets b/src/Umbraco.Web.UI.Client/.vscode/lit.code-snippets index 4920d8011b..d6e2e5ea16 100644 --- a/src/Umbraco.Web.UI.Client/.vscode/lit.code-snippets +++ b/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}", "}", "", diff --git a/src/Umbraco.Web.UI.Client/devops/generate-check-const-test/index.js b/src/Umbraco.Web.UI.Client/devops/generate-check-const-test/index.js index 56757ff716..f78147612e 100644 --- a/src/Umbraco.Web.UI.Client/devops/generate-check-const-test/index.js +++ b/src/Umbraco.Web.UI.Client/devops/generate-check-const-test/index.js @@ -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); } diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 2898815f08..73b930d3ae 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -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", diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts index d96a843293..f37ce13fdf 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/resources/resource.controller.ts @@ -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); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/temporary-file/temporary-file-manager.class.ts b/src/Umbraco.Web.UI.Client/src/packages/core/temporary-file/temporary-file-manager.class.ts index bc6bf5f340..0f4a8ab972 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/temporary-file/temporary-file-manager.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/temporary-file/temporary-file-manager.class.ts @@ -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): Promise> { const filesCompleted: Array = []; 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 }; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/temporary-file/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/temporary-file/types.ts index b471f033f0..821a770766 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/temporary-file/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/temporary-file/types.ts @@ -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 = (item: TItem) => Promise; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/import/modal/document-type-import-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/import/modal/document-type-import-modal.element.ts index 7bd699489b..97758c9fc8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/import/modal/document-type-import-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/entity-actions/import/modal/document-type-import-modal.element.ts @@ -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`
- Drag and drop your file here - + Drag and drop your file(s) into the area + + + create-as-temporary + @complete=${this.#onUploadComplete}>
`, )} `; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/dropzone.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/components/dropzone.element.ts similarity index 92% rename from src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/dropzone.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/media/dropzone/components/dropzone.element.ts index f90199879d..e12a41488b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/dropzone.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/components/dropzone.element.ts @@ -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')}>`; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/components/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/components/index.ts new file mode 100644 index 0000000000..008143e170 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/components/index.ts @@ -0,0 +1,2 @@ +export * from './input-dropzone/input-dropzone.element.js'; +export * from './dropzone.element.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/components/input-dropzone/input-dropzone.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/components/input-dropzone/input-dropzone.element.ts new file mode 100644 index 0000000000..c8de1fe129 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/components/input-dropzone/input-dropzone.element.ts @@ -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( + 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; + + #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` + + + + + + ${this.#renderUploader()} + `; + } + + #renderUploader() { + if (this.disabled) return nothing; + if (!this._progressItems?.length) return nothing; + + return html` +
+ ${repeat( + this._progressItems, + (item) => item.unique, + (item) => this.#renderPlaceholder(item), + )} + + ${this.localize.term('content_uploadClear')} + +
+ `; + } + + #renderPlaceholder(item: UmbUploadableItem) { + const file = item.temporaryFile?.file; + return html` +
+
+ ${when( + item.status === UmbFileDropzoneItemStatus.COMPLETE, + () => html``, + )} + ${when( + item.status === UmbFileDropzoneItemStatus.ERROR || + item.status === UmbFileDropzoneItemStatus.CANCELLED || + item.status === UmbFileDropzoneItemStatus.NOT_ALLOWED, + () => html``, + )} +
+
+
${file?.name ?? ''}
+
+ ${formatBytes(file?.size ?? 0, { decimals: 2 })}: + ${this.localize.number(item.progress, { maximumFractionDigits: 0 })}% +
+ ${when( + item.status === UmbFileDropzoneItemStatus.WAITING, + () => html`
`, + )} + ${when( + item.status === UmbFileDropzoneItemStatus.ERROR, + () => html`
An error occured
`, + )} + ${when(item.status === UmbFileDropzoneItemStatus.CANCELLED, () => html`
Cancelled
`)} + ${when( + item.status === UmbFileDropzoneItemStatus.NOT_ALLOWED, + () => html`
File type not allowed
`, + )} +
+
+ ${when( + item.status === UmbFileDropzoneItemStatus.WAITING, + () => html` + this.#handleCancel(item)} + label=${this.localize.term('general_cancel')}> + ${this.localize.term('general_cancel')} + + `, + )} +
+
+ `; + } + + #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; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/components/input-dropzone/input-dropzone.stories.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/components/input-dropzone/input-dropzone.stories.ts new file mode 100644 index 0000000000..346097c6ff --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/components/input-dropzone/input-dropzone.stories.ts @@ -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 = { + id: 'umb-input-dropzone', + title: 'Components/Inputs/Dropzone', + component: 'umb-input-dropzone', + args: { + disabled: false, + accept: '', + createAsTemporary: true, + }, + decorators: [(Story) => html`
${Story()}
`], + parameters: { + layout: 'centered', + actions: { + handles: ['submitted', 'change'], + }, + }, +}; + +export default meta; + +type Story = StoryObj; + +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` +
Custom slot
+
`, +}; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/constants.ts new file mode 100644 index 0000000000..df1c3a9d8b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/constants.ts @@ -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', +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/dropzone-change.event.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/dropzone-change.event.ts new file mode 100644 index 0000000000..1ba53bf4c4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/dropzone-change.event.ts @@ -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, args?: EventInit) { + super(UmbDropzoneChangeEvent.TYPE, { bubbles: false, composed: false, cancelable: false, ...args }); + this.items = items; + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/dropzone-manager.class.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/dropzone-manager.class.ts similarity index 86% rename from src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/dropzone-manager.class.ts rename to src/Umbraco.Web.UI.Client/src/packages/media/dropzone/dropzone-manager.class.ts index b58069b537..1a01cf86ad 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/dropzone-manager.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/dropzone-manager.class.ts @@ -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) { + 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) { 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 = []; 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) { diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/dropzone-submitted.event.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/dropzone-submitted.event.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/dropzone-submitted.event.ts rename to src/Umbraco.Web.UI.Client/src/packages/media/dropzone/dropzone-submitted.event.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/index.ts new file mode 100644 index 0000000000..9a15a46dc6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/index.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/manifests.ts new file mode 100644 index 0000000000..6e046c0210 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/manifests.ts @@ -0,0 +1,3 @@ +import { manifests as modalManifests } from './modals/manifests.js'; + +export const manifests: Array = [...modalManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/modals/dropzone-media-type-picker/dropzone-media-type-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/modals/dropzone-media-type-picker/dropzone-media-type-picker-modal.element.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/modals/dropzone-media-type-picker/dropzone-media-type-picker-modal.element.ts rename to src/Umbraco.Web.UI.Client/src/packages/media/dropzone/modals/dropzone-media-type-picker/dropzone-media-type-picker-modal.element.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/modals/dropzone-media-type-picker/dropzone-media-type-picker-modal.token.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/modals/dropzone-media-type-picker/dropzone-media-type-picker-modal.token.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/modals/dropzone-media-type-picker/dropzone-media-type-picker-modal.token.ts rename to src/Umbraco.Web.UI.Client/src/packages/media/dropzone/modals/dropzone-media-type-picker/dropzone-media-type-picker-modal.token.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/modals/dropzone-media-type-picker/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/modals/dropzone-media-type-picker/index.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/modals/dropzone-media-type-picker/index.ts rename to src/Umbraco.Web.UI.Client/src/packages/media/dropzone/modals/dropzone-media-type-picker/index.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/modals/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/modals/index.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/modals/index.ts rename to src/Umbraco.Web.UI.Client/src/packages/media/dropzone/modals/index.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/modals/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/modals/manifests.ts similarity index 100% rename from src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/modals/manifests.ts rename to src/Umbraco.Web.UI.Client/src/packages/media/dropzone/modals/manifests.ts diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/types.ts b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/types.ts similarity index 87% rename from src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/types.ts rename to src/Umbraco.Web.UI.Client/src/packages/media/dropzone/types.ts index f1b90a32e8..24ed77b094 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/dropzone/types.ts @@ -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', -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/media/manifests.ts index bfb213f1b4..b4f6bc4c69 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/manifests.ts @@ -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 = [ @@ -9,4 +10,5 @@ export const manifests: Array = ...mediaManifests, ...mediaTypesManifests, ...imagingManifests, + ...dropzoneManifests, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/modal/media-type-import-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/modal/media-type-import-modal.element.ts index 06973dd3a2..6bf7494ea3 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/modal/media-type-import-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/entity-actions/import/modal/media-type-import-modal.element.ts @@ -125,15 +125,19 @@ export class UmbMediaTypeImportModalLayout extends UmbModalBaseElement< label=${this.localize.term('general_remove')}> `, () => - /**TODO Add localizations */ html`
- Drag and drop your file here - + Drag and drop your file(s) into the area + + + create-as-temporary + @complete=${this.#onUploadCompleted}>
`, )} `; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.context.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.context.ts index 8353b3579e..486dada1ec 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.context.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.element.ts index e5deb42fa9..ffc8e3fbcd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/media-collection.element.ts @@ -1,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 { diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/types.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/types.ts index 78d0b0a566..06712e08d8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/types.ts @@ -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 { diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts index 3a5e187522..ac9709081d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/collection/views/grid/media-grid-collection-view.element.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts index d65a643e28..848bde04eb 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-rich-media/input-rich-media.element.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-upload-field/input-upload-field.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-upload-field/input-upload-field.element.ts index 50c283acec..7c7cd25841 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-upload-field/input-upload-field.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/components/input-upload-field/input-upload-field.element.ts @@ -69,8 +69,6 @@ export class UmbInputUploadFieldElement extends UmbLitElement { #manifests: Array = []; - #uploadAbort?: AbortController; - override updated(changedProperties: PropertyValueMap | Map) { 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 = [ diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/constants.ts index 5b8f281fe2..7c28975d0b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/constants.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/constants.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/constants.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/constants.ts deleted file mode 100644 index 4f9dd69361..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export { UMB_DROPZONE_MEDIA_TYPE_PICKER_MODAL } from './modals/dropzone-media-type-picker/dropzone-media-type-picker-modal.token.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/index.ts deleted file mode 100644 index c965489395..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './dropzone.element.js'; -export * from './dropzone-manager.class.js'; -export * from './dropzone-submitted.event.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/manifests.ts deleted file mode 100644 index c777b79000..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/dropzone/manifests.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './modals/manifests.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/index.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/index.ts index f9957ebb0d..9b7f13cc62 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/index.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/manifests.ts index 69738473e5..45d54199b1 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/manifests.ts @@ -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 = [ ...auditLogManifests, ...collectionManifests, - ...dropzoneManifests, ...entityActionsManifests, ...entityBulkActionsManifests, ...fileUploadPreviewManifests, diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts index fdd8bb21d4..3e12c0901b 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts @@ -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, diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/types.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/types.ts index c9545de5a0..9905007aba 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/types.ts @@ -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'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/vite.config.ts b/src/Umbraco.Web.UI.Client/src/packages/media/vite.config.ts index 03e52c2baa..c14c673090 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/vite.config.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/vite.config.ts @@ -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', diff --git a/src/Umbraco.Web.UI.Client/tsconfig.json b/src/Umbraco.Web.UI.Client/tsconfig.json index 512ce70e9a..9d85ebd8e6 100644 --- a/src/Umbraco.Web.UI.Client/tsconfig.json +++ b/src/Umbraco.Web.UI.Client/tsconfig.json @@ -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": [ diff --git a/src/Umbraco.Web.UI.Client/utils/all-umb-consts/imports.ts b/src/Umbraco.Web.UI.Client/utils/all-umb-consts/imports.ts deleted file mode 100644 index 0cd1f38783..0000000000 --- a/src/Umbraco.Web.UI.Client/utils/all-umb-consts/imports.ts +++ /dev/null @@ -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 - } - ]; - \ No newline at end of file