Skip to content

Commit

Permalink
feat(edit-content): Create dialog with basic structure and layout for…
Browse files Browse the repository at this point in the history
… "Select Existing File" (#30484)

### Parent Issue

#30214 

### Proposed Changes

This pull request introduces a new file selection dialog for selecting
existing files and includes several related changes to the UI components
and styles. The most important changes include the addition of new
components for the file selection dialog, updates to existing components
to integrate the new dialog, and styling adjustments.

### New Components for File Selection Dialog:

*
[`core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/components/dot-select-existing-file/components/dot-dataview/dot-dataview.component.ts`](diffhunk://#diff-064fa97792b3eda161c39afba07eaeff7ff4e019a0aa5074b3031d91e51073b9R1-R57):
Added `DotDataViewComponent` to display a table of existing files with
search functionality.
*
[`core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/components/dot-select-existing-file/components/dot-sidebar/dot-sidebar.component.ts`](diffhunk://#diff-b6e7f5a1ad7c221178b3ddf3f3dfc06021ba87b4e18ef9d7f6c6c9a6eab016d3R1-R44):
Added `DotSideBarComponent` to display a tree structure for file
navigation.
*
[`core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/components/dot-select-existing-file/dot-select-existing-file.component.ts`](diffhunk://#diff-18bf6e06cc08560259db33d84f324194172c43e47220f07b1de0990cf71077acR1-R16):
Added `DotSelectExistingFileComponent` as the main component for the
file selection dialog.

### Updates to Existing Components:

*
[`core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/dot-edit-content-file-field.component.ts`](diffhunk://#diff-3687f1cb71260d13db6856f91651dec140a064f3921bf30f342a96ee95cfda3bR37):
Integrated the new file selection dialog by adding the
`showSelectExistingFileDialog` method and importing the
`DotSelectExistingFileComponent`.
[[1]](diffhunk://#diff-3687f1cb71260d13db6856f91651dec140a064f3921bf30f342a96ee95cfda3bR37)
[[2]](diffhunk://#diff-3687f1cb71260d13db6856f91651dec140a064f3921bf30f342a96ee95cfda3bR393-R421)
*
[`core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/dot-edit-content-file-field.component.html`](diffhunk://#diff-d3f432f64fb32a0f1530f1a2ea2859614e11f4b7b87bf0fb740ebae1cc70fa3bR47):
Added a click event to trigger the file selection dialog.

### Styling Adjustments:

*
[`core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/components/dot-select-existing-file/components/dot-dataview/dot-dataview.component.scss`](diffhunk://#diff-388d8e62817fcac24e15f5b7d6a994dd6dfa418558c357a1da51cfe69682f3bcR1-R11):
Added styles for the `DotDataViewComponent`.
*
[`core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/components/dot-select-existing-file/components/dot-sidebar/dot-sidebar.component.scss`](diffhunk://#diff-5d327938b3f71b6032b0e0b7ac71603b27ed58f26e65b1911058f422a99ab62bR1-R4):
Added styles for the `DotSideBarComponent`.
*
[`core-web/libs/edit-content/src/lib/fields/dot-edit-content-file-field/components/dot-select-existing-file/dot-select-existing-file.component.scss`](diffhunk://#diff-a1e13ce1dcbd268308e7bf0bfac5910ffd944fda74cb312a33571e0eef7cb3b4R1-R18):
Added styles for the file selection dialog layout.

### Miscellaneous:

*
[`dotCMS/src/main/webapp/WEB-INF/messages/Language.properties`](diffhunk://#diff-21db9723fa4c52389731b7575f1e19bd364aa992b7e549e22c08a33456994e94R1193):
Added a new language property for the file selection dialog header.

These changes collectively enhance the file selection process by
providing a more user-friendly interface and better integration with the
existing system.


### Checklist
- [x] Tests
- [x] Translations
- [x] Security Implications Contemplated (add notes if applicable)

### Screenshots



https://github.com/user-attachments/assets/013f5bf6-a38e-4a59-963a-60149c0ab6ee
  • Loading branch information
nicobytes authored and spbolton committed Nov 11, 2024
1 parent 73623f2 commit ce7b5a6
Show file tree
Hide file tree
Showing 15 changed files with 457 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@use "variables" as *;

.p-icon-field {
.p-input-icon {
position: absolute;
top: 50%;
transform: translateY(-50%);
}

&-left {
.p-input-icon:first-of-type {
left: $spacing-2;
color: $color-palette-gray-600;
}

> .p-inputtext {
padding-left: $spacing-6;
}

&.p-float-label > label {
left: $spacing-6;
}
}

&-right {
.p-input-icon:last-of-type {
right: $spacing-2;
color: $color-palette-gray-600;
}

> .p-inputtext {
padding-right: $spacing-6;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
@use "selectbutton";
@use "slider";
@use "treeselect";
@use "iconfield";
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<p-table
[value]="$data()"
[loading]="$loading()"
[paginator]="true"
[rows]="7"
styleClass="p-datatable-lg flex flex-column h-full justify-content-between">
<ng-template pTemplate="caption">
<div class="flex">
<p-iconField iconPosition="left">
<p-inputIcon styleClass="pi pi-search" />
<input pInputText type="text" placeholder="Search keyword" />
</p-iconField>
</div>
</ng-template>
<ng-template pTemplate="header">
<tr class="file-selector__table_header">
<th scope="col">{{ 'dot.file.field.dialog.select.existing.file.table.title' | dm }}</th>
<th scope="col">
{{ 'dot.file.field.dialog.select.existing.file.table.modified.by' | dm }}
</th>
<th scope="col">
{{ 'dot.file.field.dialog.select.existing.file.table.last.modified' | dm }}
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-content>
<tr class="h-4rem">
<td>
<div class="flex gap-1 align-items-center">
<p-image
loading="lazy"
[preview]="true"
styleClass="image"
[src]="content.image"
[alt]="content.title"
width="40" />

<p class="m-0">{{ content.title }}</p>
</div>
</td>
<td>{{ content.modifiedBy }}</td>
<td>{{ content.lastModified | date }}</td>
</tr>
</ng-template>
<ng-template pTemplate="loadingbody" let-columns="columns">
<tr class="h-4rem">
@for (col of columns; track $index) {
<td>
<p-skeleton />
</td>
}
</tr>
</ng-template>
</p-table>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@use "variables" as *;

:host {
height: 100%;
display: block;
}
::ng-deep {
p-table {
.p-datatable .p-datatable-header {
background-color: $color-palette-gray-100;
}
}
}

.file-selector__table_header {
th {
font-weight: $font-weight-bold;
background-color: $color-palette-gray-100;
}
}
.img {
max-inline-size: 100%;
block-size: auto;
aspect-ratio: 2/1;
object-fit: cover;
object-position: top center;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { DatePipe, NgOptimizedImage } from '@angular/common';
import { ChangeDetectionStrategy, Component, input } from '@angular/core';

import { ButtonModule } from 'primeng/button';
import { DataViewModule } from 'primeng/dataview';
import { IconFieldModule } from 'primeng/iconfield';
import { ImageModule } from 'primeng/image';
import { InputIconModule } from 'primeng/inputicon';
import { InputTextModule } from 'primeng/inputtext';
import { SkeletonModule } from 'primeng/skeleton';
import { TableModule } from 'primeng/table';
import { TagModule } from 'primeng/tag';

import { DotMessagePipe } from '@dotcms/ui';

import { Content } from '../../store/select-existing-file.store';

@Component({
selector: 'dot-dataview',
standalone: true,
imports: [
DataViewModule,
TagModule,
ButtonModule,
TableModule,
IconFieldModule,
InputIconModule,
InputTextModule,
SkeletonModule,
ImageModule,
NgOptimizedImage,
DatePipe,
DotMessagePipe
],
templateUrl: './dot-dataview.component.html',
styleUrls: ['./dot-dataview.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DotDataViewComponent {
/**
* Represents an observable stream of content data.
*
* @type {Observable<Content[]>}
* @alias data
* @required
*/
$data = input.required<Content[]>({ alias: 'data' });
/**
* A boolean observable that indicates the loading state.
* This is typically used to show or hide a loading indicator in the UI.
*
* @type {boolean}
*/
$loading = input.required<boolean>({ alias: 'loading' });
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p-tree [value]="$folders()" class="w-full h-full" styleClass="flex h-full" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
:host {
height: 100%;
display: flex;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ChangeDetectionStrategy, Component, input } from '@angular/core';

import { TreeNode } from 'primeng/api';
import { TreeModule } from 'primeng/tree';

@Component({
selector: 'dot-sidebar',
standalone: true,
imports: [TreeModule],
templateUrl: './dot-sidebar.component.html',
styleUrls: ['./dot-sidebar.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DotSideBarComponent {
/**
* An observable that emits an array of TreeNode objects representing folders.
*
* @type {Observable<TreeNode[]>}
* @alias folders
*/
$folders = input.required<TreeNode[]>({ alias: 'folders' });
/**
* Represents a loading state for the component.
*
* @type {boolean}
* @alias loading
*/
$loading = input.required<boolean>({ alias: 'loading' });
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<div class="file-selector flex flex-column gap-3">
<div class="file-selector__main grid grid-nogutter flex-grow-1 overflow-hidden">
<div class="col-3 file-selector__sidebar">
<dot-sidebar [folders]="store.folders().data" [loading]="store.foldersIsLoading()" />
</div>
<div class="col">
<dot-dataview [data]="store.content().data" [loading]="store.contentIsLoading()" />
</div>
</div>
<div class="flex justify-content-end flex-none flex-wrap gap-3">
<p-button
(click)="closeDialog()"
[label]="'dot.file.field.dialog.select.existing.file.actions.cancel' | dm"
[text]="true"
severity="primary" />
<p-button
[label]="'dot.file.field.dialog.select.existing.file.actions.upload' | dm"
[text]="true"
[outlined]="true"
severity="primary" />
<p-button
[label]="'dot.file.field.dialog.select.existing.file.actions.add' | dm"
severity="primary" />
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@use "variables" as *;

.file-selector {
height: 43rem;
.file-selector__sidebar {
border-right: $field-border-size solid $color-palette-gray-400;
::ng-deep {
.p-tree {
border: 0px;
}
}
}
.file-selector__main {
margin-top: 1px;
border-radius: $border-radius-md;
border: $field-border-size solid $color-palette-gray-400;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { ChangeDetectionStrategy, Component, inject, OnInit } from '@angular/core';

import { ButtonModule } from 'primeng/button';
import { DynamicDialogRef } from 'primeng/dynamicdialog';

import { DotMessagePipe } from '@dotcms/ui';

import { DotDataViewComponent } from './components/dot-dataview/dot-dataview.component';
import { DotSideBarComponent } from './components/dot-sidebar/dot-sidebar.component';
import { SelectExisingFileStore } from './store/select-existing-file.store';

@Component({
selector: 'dot-select-existing-file',
standalone: true,
imports: [DotSideBarComponent, DotDataViewComponent, ButtonModule, DotMessagePipe],
templateUrl: './dot-select-existing-file.component.html',
styleUrls: ['./dot-select-existing-file.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [SelectExisingFileStore]
})
export class DotSelectExistingFileComponent implements OnInit {
/**
* Injects the SelectExistingFileStore into the component.
*
* @readonly
* @type {SelectExistingFileStore}
*/
/**
* A readonly property that injects the `SelectExisingFileStore` service.
* This store is used to manage the state and actions related to selecting existing files.
*/
readonly store = inject(SelectExisingFileStore);
/**
* A reference to the dynamic dialog instance.
* This is a read-only property that is injected using Angular's dependency injection.
* It provides access to the dialog's methods and properties.
*/
readonly #dialogRef = inject(DynamicDialogRef);

ngOnInit() {
this.store.loadContent();
this.store.loadFolders();
}

/**
* Cancels the current file upload and closes the dialog.
*
* @remarks
* This method is used to terminate the ongoing file upload process and
* close the associated dialog reference.
*/
closeDialog(): void {
this.#dialogRef.close();
}
}
Loading

0 comments on commit ce7b5a6

Please sign in to comment.