Skip to content

feat(content-drive): prompt Asset vs File on upload (#35575)#36243

Open
zJaaal wants to merge 6 commits into
mainfrom
35575-task-content-drive-upload-button-asset-vs-file-type-selection
Open

feat(content-drive): prompt Asset vs File on upload (#35575)#36243
zJaaal wants to merge 6 commits into
mainfrom
35575-task-content-drive-upload-button-asset-vs-file-type-selection

Conversation

@zJaaal

@zJaaal zJaaal commented Jun 19, 2026

Copy link
Copy Markdown
Member

Proposed Changes

Closes #35575.

When uploading to a folder with no preference set, Content Drive now prompts the user to choose between Asset (dotAsset) and File (FileAsset) before the upload runs, and sends the selected base type to the upload endpoint instead of the hardcoded dotAsset. This applies to both upload entry points: the Upload button and OS drag-and-drop.

Behavior

  • Upload button: choose a type → the OS file picker opens → the file uploads as the chosen type.
  • Drag-and-drop: drop files → choose a type → the dropped files upload as the chosen type.
  • The selector defaults to Assets (marked Recommended); Files maps to FileAsset.
  • Backend resolves the type from the contentlet contentType field; FileAsset is the File Asset content-type variable (matches DEFAULT_FILE_ASSET_TYPES).
Screen.Recording.2026-06-18.at.2.34.07.PM-1.mov

Changes

  • New dot-content-drive-dialog-upload-selector dialog, wired through the shell's UPLOAD_SELECTOR dialog. It emits the full selection (target folder + content type + files) so a future per-folder "remember" preference ([TASK] Content Drive: Persist default upload base type on folder (remember preference + edit folder fields) #35578) can reuse it without rework.
  • DotUploadFileService.uploadDotAsset takes an optional contentType (defaults to dotAsset; backward compatible with existing callers).
  • Renamed onAddNewDotAsset / addNewDotAssetonUpload / upload (no more hardcoded dotAsset in handler/event names).
  • Fixed two pre-existing layout bugs noticed during review: dropzone overlay icon centering, and the locale chip wrapping at narrow widths.

Out of scope (tracked in epic #35436)

Folder-level preferences/inheritance (#35577), the "Remember for this folder" checkbox (#35578), dynamic button label, MIME-type routing, and multi-file upload.

Testing

  • New spec for the upload selector dialog (option rendering, Recommended chip, default selection, emitted selection for Asset/File, Cancel).
  • Shell spec reworked to the dialog flow (driven via UI events): opening the selector from button/drag-drop/sidebar, drag-drop upload as dotAsset/FileAsset, root upload, message handling, multi-file warning, and the button flow (pick → picker → upload).
  • Upload service spec covers the default and explicit contentType.
  • portlets-content-drive: 666 passing; data-access: 690 passing. Lint clean.

Manual UI verification of the live upload + i18n copy is pending a backend message-cache reload.

🤖 Generated with Claude Code

Uploading to a folder with no preference now prompts the user to choose
between Asset (dotAsset) and File (FileAsset) before the upload runs,
for both the Upload button and OS drag-and-drop. The selected base type
is sent to the upload endpoint instead of the hardcoded dotAsset.

- Parameterize DotUploadFileService.uploadDotAsset with a contentType
  (defaults to dotAsset; backward compatible)
- Add the dot-content-drive-dialog-upload-selector dialog (Assets
  recommended + selected by default, Files), wired through the shell's
  UPLOAD_SELECTOR dialog and emitting the full selection (folder + type
  + files) so a future per-folder "remember" can reuse it
- Rename onAddNewDotAsset/addNewDotAsset to onUpload/upload
- Fix pre-existing dropzone overlay icon centering and the locale chip
  wrapping at narrow widths
- Tests for the dialog, both upload flows, and the service param

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@claude

claude Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Claude finished @zJaaal's task in 1m 48s —— View job


Rollback Safety Analysis

  • Read rollback-unsafe categories reference
  • Get full PR diff
  • Analyze diff against all categories
  • Apply appropriate label

Result: ✅ Safe To Rollback

All 16 changed files are pure frontend (Angular/TypeScript) and i18n properties. The diff was checked against every unsafe category:

Category Check Result
C-1 Structural Data Model Change No runonce tasks, no DB schema changes ✅ Not present
C-2 Elasticsearch Mapping Change No ES mapping code or reindex tasks ✅ Not present
C-3 Content JSON Model Version Bump No CURRENT_MODEL_VERSION changes ✅ Not present
C-4 DROP TABLE / DROP COLUMN No DDL statements ✅ Not present
H-1 One-Way Data Migration No UPDATE … SET transformations ✅ Not present
H-2 RENAME TABLE / COLUMN No renames ✅ Not present
H-3 PK Restructuring No PK changes ✅ Not present
H-4 New ContentType Field Type No new Java field types registered ✅ Not present
H-5 Binary Storage Provider Change No storage config changes ✅ Not present
H-6 DROP PROCEDURE / FUNCTION No stored procedure changes ✅ Not present
H-7 NOT NULL column without default No DB schema additions ✅ Not present
H-8 VTL Viewtool Contract Change No viewtool changes ✅ Not present
M-1 Column Type Change No DDL ✅ Not present
M-2 Push Bundle XML Change No bundler changes ✅ Not present
M-3 REST/GraphQL API Contract Change No REST endpoint changes (only internal Angular component APIs renamed: addNewDotAssetupload) ✅ Not present
M-4 OSGi Interface Change No OSGi changes ✅ Not present

Summary: This PR is entirely frontend — new Angular dialog component, updated shell wiring, renamed component outputs, one Language.properties i18n key addition, and test updates. The only backend touch is Language.properties (additive, no keys removed). Rolling back to N-1 simply reverts to the hardcoded dotAsset upload behavior with no data loss, schema impact, or API breakage.

Label added: AI: Safe To Rollback

@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

🤖 Bedrock Review — deepseek.v3.2

[🟡 Medium] core-web/libs/data-access/src/lib/dot-upload-file/dot-upload-file.service.ts:124 — The uploadDotAsset method's contentType parameter defaults to 'dotAsset' but is not validated. If an invalid or unsupported content type is passed, the backend call may fail unexpectedly. Consider adding validation or at least documenting allowed values.

[🟡 Medium] core-web/libs/portlets/dot-content-drive/portlet/src/lib/dot-content-drive-shell/dot-content-drive-shell.component.ts:495 — In uploadDotAsset, the hostFolder parameter defaults to an empty string '' when hostFolder?.id is undefined. This may be intentional for root uploads, but ensure the backend correctly handles an empty string as a valid host folder identifier.

[🟡 Medium] core-web/libs/portlets/dot-content-drive/portlet/src/lib/dot-content-drive-shell/dot-content-drive-shell.component.ts:528 — The uploadDotAsset success callback uses uploadedContentType from the response for the success message detail. This is fine, but note that it's different from the requested contentType parameter; ensure this distinction is clear in logs or debugging.

[🟠 High] core-web/libs/portlets/dot-content-drive/portlet/src/lib/dot-content-drive-shell/dot-content-drive-shell.component.ts:415-417 — In onFileChange, this.$activeSelection.set(undefined) is called before checking if (!files || files.length === 0 || !selection). If the file picker is cancelled, the selection is cleared, but if it's reopened with a stale selection, it won't work because selection is already undefined. This is correct behavior, but ensure there's no race condition where $activeSelection could be set after the check (unlikely due to synchronous nature). No bug, but note for future async changes.

[🟡 Medium] core-web/libs/portlets/dot-content-drive/portlet/src/lib/dot-content-drive-shell/dot-content-drive-shell.component.spec.ts:647-1860 — The test file has extensive changes replacing old upload logic with new flow tests. Ensure all previous edge cases (e.g., multiple files, error handling, site root uploads) are still covered in the new tests. The diff shows they are, but verify no regression in coverage.

[🟡 Medium] core-web/libs/portlets/dot-content-drive/portlet/src/lib/shared/models.ts:10 — The new DotContentDriveUploadContentType type is derived from UPLOAD_SELECTOR_OPTIONS. This ensures type safety, but note that if UPLOAD_SELECTOR_OPTIONS changes, the type updates automatically. This is good design.

[🟡 Medium] core-web/libs/portlets/dot-content-drive/portlet/src/lib/components/dialogs/dot-content-drive-dialog-upload-selector/dot-content-drive-dialog-upload-selector.component.ts:69 — The $canContinue computed property returns !!this.$selectedType(). Since $selectedType defaults to the first option, it will always be truthy, making the Continue button enabled even if somehow $selectedType becomes undefined. This is fine given the UI constraints, but consider if a more robust check is needed (e.g., ensuring the selected type is in the options list).

[🟡 Medium] core-web/libs/portlets/dot-content-drive/portlet/src/lib/components/dialogs/dot-content-drive-dialog-upload-selector/dot-content-drive-dialog-upload-selector.component.html:24 — The @if (option.recommended) block uses a hardcoded translation key 'content-drive.dialog.upload-selector.recommended'. Ensure this key exists in the Language.properties file; the diff shows it's added, so no issue.

[🟡 Medium] core-web/libs/portlets/dot-content-drive/ui/src/lib/dot-folder-list-view/dot-folder-list-view.component.html:120 — Added class="whitespace-nowrap" to a p-tag for language display. This is a styling fix; ensure it doesn't break existing layouts.

[🟡 Medium] core-web/libs/portlets/dot-content-drive/portlet/src/lib/components/dot-content-drive-dropzone/dot-content-drive-dropzone.component.html:4-12 — Changed icon wrapper from a single <i> to a <div> wrapping an <i>. This is a styling adjustment; verify the icon still displays correctly across browsers.

No critical bugs, security issues, or violations of dotCMS conventions found in the diff. The changes introduce a new upload type selector dialog and refactor upload logic to support both dotAsset and FileAsset content types, with comprehensive tests.


Run: #27842643608 · tokens: in: 17851 · out: 1073 · total: 18924

- Type the upload selection's contentType as a union derived from
  UPLOAD_SELECTOR_OPTIONS so it can't drift or accept arbitrary values
- Rename the shadowed contentType in the upload success handler

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@zJaaal

zJaaal commented Jun 19, 2026

Copy link
Copy Markdown
Member Author

Thanks for the review — went through each item.

Addressed (e097bfa):

  • 🟡 models.tsDotContentDriveUploadSelection.contentType is now a union (DotContentDriveUploadContentType) derived from UPLOAD_SELECTOR_OPTIONS, so it can't accept arbitrary strings and stays in sync with the rendered choices. This also covers the "validate the contentType param" point — the only producer is the typed selector.
  • 🟡 shell.component.ts — renamed the shadowed contentType in the upload success handler (contentType: uploadedContentType) for clarity.

Intentional / no change (with rationale):

  • 🟡 hostFolder ?? '' — empty string is the established "site root" convention here (same as DotUploadFileService.publishContent); the backend resolves it to the current host.
  • 🟡 $canContinue — kept as a defensive guard so onContinue and the disabled state stay correct if the default selection ever changes; harmless given a radio can't be deselected today.
  • 🟡 onFileChange reset ordering — the reset and input.value = '' are adjacent synchronous statements (no await/async between them), so a finally block isn't needed; resetting before the guard is deliberate so a re-opened picker can't reuse a stale selection.
  • 🟡 duplicated !files?.length checks — each guard serves a distinct purpose: resolveFilesUpload needs it before reading files.length, and uploadFile needs it to narrow files before files[0]. They're type-narrowing guards, not redundant validation.
  • 🟡 hardcoded dotAsset/FileAsset in UPLOAD_SELECTOR_OPTIONS — these are dotCMS's canonical base content-type variables (matches DEFAULT_FILE_ASSET_TYPES); they're the single source the union type now derives from.
  • 🟠 createFileList test helper — test-only; it replicates the length/indexed-access/item() surface the implementation actually uses. Fine for these specs.
  • 🟡 jest not imported in the dialog spec — jest/afterEach are ambient globals here, consistent with the sibling dot-content-drive-dialog-content-type-selector.component.spec.ts. Tests pass.

— Reply drafted by Claude (Claude Code) on behalf of @zJaaal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI: Safe To Rollback Area : Frontend PR changes Angular/TypeScript frontend code

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

[TASK] Content Drive: Upload button — Asset vs File type selection

1 participant