Skip to content

Commit f3ab183

Browse files
artisticlightwilliamh890Copilot
authored
Andy/radio button toggle (#2378)
* Add ability to update a jobs project name * fix: formatting * Add ability to nuke all loaded jobs * Make Help more easily seen on Filter's panel. * DS-6336 Text modified to be translatable. * Lint space * feat: Update to use jobs patch endpoint * Update src/app/components/filters-dropdown/dataset-filters/dataset-filters.component.scss Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Round 1 of revamping the UI * Fix console error related to translation. * Bulk rename uses new dialog * npm run lint -- --fix * On Demand search reloads after bulk rename * npm run lint -- --fix * Resolving issues from merging with test * Snackbar message for renaming jobs * Adding multi-lingual support to rename dialog And a few other UI tweaks. * Edit Validation Added checks for empty project name entry or only spaces. Also validate that the jobs were successfully renamed and provided error handling. Will provide error notification with toast. * Update src/app/services/hyp3/hyp3-api.service.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/app/store/scenes/scenes.action.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix for flight direction graphics not appearing in Displacement I think this is an unreported bug resulting from the recent Angular upgrade. * Show projects that are going to be renamed with the bulk operation. * Update uniqueProjectNames filtering * Fix: update job count in dialog * Fix single job rename * Many Changes * Added list of projects and associated job counts in a sortable table * Limited project name input to 100 characters * Prevent user from changing names of projects for other users * Progress Bar I've implemented a two-phase dialog that handles the rename operation internally with a determinate progress bar. * Deterministic Progress Bar The Project Rename dialog box now is augmented with a couple more screens indicating renaming progress and completion. * UI Improvements * Auto-focus the input field * Show the new name in the confirmation message * Show specific project names if failed I've implemented the feature to show which specific project names failed to rename in the completion phase. * Show Time Estimate for Bulk Rename Completion I've implemented the estimated time remaining feature for large batch rename operations. Here's what was added: How it works: The estimated time is calculated based on the elapsed time and number of completed batches It only displays for operations with 1000+ jobs (to avoid showing for small, quick operations) The time is displayed in a user-friendly format (e.g., "< 1 min", "~1 min", "~5 min") * Project Rename Title Updated Updated the table to William's suggestions. * npm run lint -- --fix * Update src/app/store/scenes/scenes.action.ts Co-authored-by: William Horn <wbhorn@alaska.edu> * Update src/app/services/hyp3/hyp3-api.service.ts Co-authored-by: William Horn <wbhorn@alaska.edu> * Created three named interfaces at the top of hyp3-api.service.ts * RenameProgressInfo - Progress info with percent and estimated time remaining * RenameResult - Final result with success/failed counts and failed project names *RenameWithProgressResult - The composite return type containing both observables I also changed a 'sneaky' 3 into a constant * Update src/app/components/shared/project-name-dialog/project-name-dialog.component.ts Co-authored-by: William Horn <wbhorn@alaska.edu> * Tyler Suggestions Fixed - Red toast regression Fixed - Missing unnamed projects * Tyler Suggestions #2 Fixed - Empty string validation feedback Fixed - Checkbox disclaimer with empty string * Tyler Suggestions #3 Fixed - Remove dialog service abstraction Fixed - Convert getter to signal/computed * Tyler Suggestions #4 Fixed - Use SubSink pattern consistently Fixed - Moved constructor logic to ngOnInit * Tyler Suggestions #5 Fixed - Material Table with Sorting in-place Reviewing the idea of using the Material Stepper consideration, I don't think it is a good fit. The phases are not user-navigated steps, they're system-driven and there is no option for backward navigation. * npm run lint -- --fix * Conformity & Best Practices #2 - Removed stale SCSS styles: Cleaned up .sortable, .sort-indicator, .projects-table-body-container, and custom table styling that was no longer needed after switching to Material table * Made dialog injects private: Changed dialogRef and data from public to private to match codebase pattern * Added readonly to displayedColumns: Added readonly modifier since the array never changes * Fixed track function: Changed track name to track $index to handle potential duplicate project names in the failed list * Made "(unnamed)" multilingual * Tweaks Made the Project Rename table sorted by Project Name by default and eliminated the use of ::ng-deep in the Project Rename scss files. * Conformity & Best Practices * Removed stale SCSS styles: Cleaned up .sortable, .sort-indicator, .projects-table-body-container, and custom table styling that was no longer needed after switching to Material table * Made dialog injects private: Changed dialogRef and data from public to private to match codebase pattern * Added readonly to displayedColumns: Added readonly modifier since the array never changes * Fixed track function: Changed track name to track $index to handle potential duplicate project names in the failed list * Made "(unnamed)" multilingual * Tweaks Made the Project Rename table sorted by Project Name by default and eliminated the use of ::ng-deep in the Project Rename scss files. * npm run lint -- --fix * Made the table header 'sticky' * Fixed Table Header for Dark-Theme * Show estimated time for 5+ jobs It was 1000+ before but Tools wants to see it always. * Warn about Abort I added a @HostListener for the window:beforeunload event that triggers only when the dialog is in the processing phase. This will: - Show the browser's native "Leave site?" confirmation dialog when the user tries to close the tab/window or navigate away - Only trigger during the processing phase - users can freely close during input, complete, or error phases - Let the browser handle the UI (modern browsers don't allow custom messages for security reasons) * Add toggle for removing project names in update dialog * feat(project-name-dialog): replace button toggle with radio buttons - Replace mat-button-toggle-group with mat-radio-group for cleaner UX - Input field now visually nested under "Rename" radio option - Add singular/plural translation keys for radio labels (en, es, de) - Add accessible aria-label to radio group - Update styles for radio group layout and disabled state - Add docs/ to .gitignore * Update src/assets/i18n/es.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/app/components/shared/project-name-dialog/project-name-dialog.component.scss Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Bug Fix A single job rename didn't reflect the count of '1' in the dialog for renaming a job. It now does. --------- Co-authored-by: William Horn <wbhorn@alaska.edu> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 478b6f4 commit f3ab183

7 files changed

Lines changed: 124 additions & 37 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,4 @@ local-serve.sh
4646
.claude/
4747
CLAUDE.md
4848
TRANSLATIONS_SCRATCH.md
49+
docs/

src/app/components/shared/project-name-dialog/project-name-dialog.component.html

Lines changed: 72 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,52 @@ <h2 class="dialog-title">
1616

1717
<form (ngSubmit)="onSave()">
1818
<mat-dialog-content>
19-
<mat-form-field class="project-name-field">
20-
<mat-label>{{ 'PROJECT_NAME' | translate }}</mat-label>
21-
<input
22-
#projectNameInput
23-
matInput
24-
[ngModel]="projectName()"
25-
(ngModelChange)="projectName.set($event)"
26-
name="projectName"
27-
maxlength="100"
28-
required
29-
[disabled]="isDisabledByUserFilter"
30-
/>
31-
<mat-hint align="end">{{ projectName()?.length || 0 }}/100</mat-hint>
32-
@if (!projectName()?.trim()) {
33-
<mat-error>{{ 'PROJECT_NAME_REQUIRED' | translate }}</mat-error>
34-
} @else if (projectName()?.length >= 100) {
35-
<mat-error>{{ 'PROJECT_NAME_MAX_LENGTH' | translate }}</mat-error>
36-
}
37-
</mat-form-field>
19+
<mat-radio-group
20+
[ngModel]="projectEditType()"
21+
(ngModelChange)="projectEditType.set($event)"
22+
name="projectEditType"
23+
class="project-edit-radio-group"
24+
aria-label="Project edit action"
25+
>
26+
<mat-radio-button value="edit">
27+
@if (jobCount <= 1) {
28+
{{ 'RENAME_JOB_TO' | translate }}
29+
} @else {
30+
{{ 'RENAME_JOBS_TO' | translate: { count: jobCount } }}
31+
}
32+
</mat-radio-button>
33+
34+
<mat-form-field
35+
class="project-name-field"
36+
[class.disabled]="isRemoveMode()"
37+
>
38+
<mat-label>{{ 'PROJECT_NAME' | translate }}</mat-label>
39+
<input
40+
#projectNameInput
41+
matInput
42+
[ngModel]="projectName()"
43+
(ngModelChange)="projectName.set($event)"
44+
name="projectName"
45+
maxlength="100"
46+
required
47+
[disabled]="isDisabledByUserFilter || isRemoveMode()"
48+
/>
49+
<mat-hint align="end">{{ projectName()?.length || 0 }}/100</mat-hint>
50+
@if (!projectName()?.trim()) {
51+
<mat-error>{{ 'PROJECT_NAME_REQUIRED' | translate }}</mat-error>
52+
} @else if (projectName()?.length >= 100) {
53+
<mat-error>{{ 'PROJECT_NAME_MAX_LENGTH' | translate }}</mat-error>
54+
}
55+
</mat-form-field>
56+
57+
<mat-radio-button value="remove">
58+
@if (projectCount <= 1) {
59+
{{ 'REMOVE_PROJECT_NAME' | translate }}
60+
} @else {
61+
{{ 'REMOVE_PROJECT_NAMES' | translate: { count: projectCount } }}
62+
}
63+
</mat-radio-button>
64+
</mat-radio-group>
3865

3966
@if (dataSource.data.length > 0) {
4067
<p class="projects-label bold">
@@ -86,18 +113,32 @@ <h2 class="dialog-title">
86113
[(ngModel)]="confirmationChecked"
87114
name="confirmationChecked"
88115
>
89-
{{
90-
(projectCount === 1
91-
? 'CONFIRM_RENAME_SINGLE'
92-
: 'CONFIRM_RENAME_MULTIPLE'
93-
)
94-
| translate
95-
: {
96-
projectCount: projectCount,
97-
jobCount: jobCount,
98-
newName: projectName()?.trim(),
99-
}
100-
}}
116+
@if (isEditMode()) {
117+
{{
118+
(projectCount === 1
119+
? 'CONFIRM_RENAME_SINGLE'
120+
: 'CONFIRM_RENAME_MULTIPLE'
121+
)
122+
| translate
123+
: {
124+
projectCount: projectCount,
125+
jobCount: jobCount,
126+
newName: projectName()?.trim(),
127+
}
128+
}}
129+
} @else {
130+
{{
131+
(projectCount === 1
132+
? 'CONFIRM_REMOVE_SINGLE'
133+
: 'CONFIRM_REMOVE_MULTIPLE'
134+
)
135+
| translate
136+
: {
137+
projectCount: projectCount,
138+
jobCount: jobCount,
139+
}
140+
}}
141+
}
101142
</mat-checkbox>
102143
}
103144
}

src/app/components/shared/project-name-dialog/project-name-dialog.component.scss

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,34 @@ app-project-name-dialog {
2626
}
2727
}
2828

29+
// Radio group layout for edit/remove toggle
30+
.project-edit-radio-group {
31+
display: flex;
32+
flex-direction: column;
33+
gap: 8px;
34+
margin-bottom: 16px;
35+
}
36+
2937
.project-name-field {
30-
width: 100%;
38+
margin-left: 32px;
39+
width: calc(100% - 32px);
3140

3241
.mat-mdc-text-field-wrapper {
3342
padding-top: 0;
3443
}
44+
45+
// Subtle disabled state when "Remove" is selected
46+
&.disabled {
47+
opacity: 0.5;
48+
pointer-events: none;
49+
}
50+
}
51+
52+
// Radio button label sizing
53+
.mat-mdc-radio-button {
54+
.mdc-label {
55+
font-size: 14px;
56+
}
3557
}
3658

3759
.projects-label {

src/app/components/shared/project-name-dialog/project-name-dialog.component.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
MatRowDef,
3838
MatRow,
3939
} from '@angular/material/table';
40+
import { MatRadioModule } from '@angular/material/radio';
4041
import { MatSort, MatSortModule } from '@angular/material/sort';
4142
import { TranslateModule, TranslateService } from '@ngx-translate/core';
4243
import { SubSink } from 'subsink';
@@ -92,6 +93,7 @@ export interface ProjectNameDialogResult {
9293
MatRowDef,
9394
MatRow,
9495
TranslateModule,
96+
MatRadioModule,
9597
],
9698
})
9799
export class ProjectNameDialogComponent
@@ -125,9 +127,14 @@ export class ProjectNameDialogComponent
125127
public successCount = 0;
126128
public failedCount = 0;
127129
public failedProjectNames: string[] = [];
130+
public projectEditType = signal<'edit' | 'remove'>('edit');
128131

129132
// Computed values (only recalculate when dependencies change)
130-
public isValid = computed(() => this.projectName().trim().length > 0);
133+
public isEditMode = computed(() => this.projectEditType() === 'edit');
134+
public isRemoveMode = computed(() => this.projectEditType() === 'remove');
135+
public isValid = computed(
136+
() => this.projectName().trim().length > 0 || this.isRemoveMode(),
137+
);
131138

132139
public formattedTimeRemaining = computed(() => {
133140
// Only show estimated time for operations of 5+ jobs
@@ -157,7 +164,7 @@ export class ProjectNameDialogComponent
157164
}
158165

159166
const products = this.data?.products;
160-
this.jobCount = products?.length;
167+
this.jobCount = products?.length ?? 1;
161168

162169
if (products) {
163170
const unnamedLabel = this.translateService.instant(
@@ -204,7 +211,7 @@ export class ProjectNameDialogComponent
204211
return;
205212
}
206213

207-
const trimmedName = this.projectName().trim();
214+
const trimmedName = this.isEditMode() ? this.projectName().trim() : null;
208215

209216
// If no products, just return the name (single-file rename flow)
210217
if (!this.data.products || this.data.products.length === 0) {

src/assets/i18n/de.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,8 @@
597597
"REMOVE_FILE_FROM_DOWNLOADS": "Datei aus Downloads entfernen",
598598
"REMOVE_FILE_FROM_QUEUE": "Datei aus der Warteschlange entfernen",
599599
"REMOVE_JOB": "Job entfernen",
600+
"REMOVE_PROJECT_NAME": "Projektname entfernen",
601+
"REMOVE_PROJECT_NAMES": "{{count}} Projektnamen entfernen",
600602
"REMOVE_RED_EYE": "remove_red_eye",
601603
"REMOVE_SCENE_FILES_FROM_DOWNLOADS": "Entfernen von Szenendateien aus Downloads",
602604
"RESAMPLED_DEM_SRTM_OR_NED_USED_FOR_RTC_PROCESSING": "Resampled DEM (SRTM oder NED), das für die RTC-Verarbeitung verwendet wird.",
@@ -609,6 +611,8 @@
609611
"RENAME_ALL_FAILED": "{{count}} Auftrag/Aufträge konnten nicht umbenannt werden.",
610612
"RENAME_COMPLETE": "Umbenennung abgeschlossen",
611613
"RENAME_ERROR": "Beim Umbenennen der Aufträge ist ein Fehler aufgetreten.",
614+
"RENAME_JOB_TO": "Job umbenennen zu:",
615+
"RENAME_JOBS_TO": "{{count}} Jobs umbenennen zu:",
612616
"RENAME_PARTIAL_SUCCESS": "{{success}} Auftrag/Aufträge umbenannt. {{failed}} fehlgeschlagen.",
613617
"RENAME_SUCCESS": "{{count}} Auftrag/Aufträge erfolgreich umbenannt.",
614618
"RENAMING_JOBS": "Aufträge werden umbenannt...",

src/assets/i18n/en.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@
126126
"CANNOT_RENAME_PROJECTS_FOR": "You cannot rename projects for",
127127
"CONFIRM_RENAME_MULTIPLE": "Yes! I really want to rename these {{projectCount}} projects ({{jobCount}} jobs) to \"{{newName}}\".",
128128
"CONFIRM_RENAME_SINGLE": "Yes! I really want to rename this 1 project ({{jobCount}} jobs) to \"{{newName}}\".",
129+
"CONFIRM_REMOVE_MULTIPLE": "Yes! I really want to remove the names from these {{projectCount}} projects ({{jobCount}} jobs).",
130+
"CONFIRM_REMOVE_SINGLE": "Yes! I really want to remove the project name from this project ({{jobCount}} jobs).",
129131
"CENTER_COLUMN_AND_FILES_COLUMN_RIGHT_WILL_POPULATE": "(center column) and Files column (right) will populate.",
130132
"CHARACTERS": "characters",
131133
"CHART": "Chart",
@@ -713,6 +715,8 @@
713715
"REMOVE_FILE_FROM_DOWNLOADS": "Remove file from downloads",
714716
"REMOVE_FILE_FROM_QUEUE": "Remove file from queue",
715717
"REMOVE_JOB": "Remove job",
718+
"REMOVE_PROJECT_NAME": "Remove project name",
719+
"REMOVE_PROJECT_NAMES": "Remove {{count}} project names",
716720
"REMOVE_RED_EYE": "remove_red_eye",
717721
"REMOVE_SCENE_FILES_FROM_DOWNLOADS": "Remove scene files from downloads",
718722
"REMOVE_SERIES": "Remove Series",
@@ -728,6 +732,8 @@
728732
"RENAME_ALL_FAILED": "Failed to rename {{count}} job(s).",
729733
"RENAME_COMPLETE": "Rename Complete",
730734
"RENAME_ERROR": "An error occurred while renaming jobs.",
735+
"RENAME_JOB_TO": "Rename job to:",
736+
"RENAME_JOBS_TO": "Rename {{count}} jobs to:",
731737
"RENAME_PARTIAL_SUCCESS": "Renamed {{success}} job(s). {{failed}} failed.",
732738
"RENAME_SUCCESS": "Successfully renamed {{count}} job(s).",
733739
"RENAMING_JOBS": "Renaming jobs...",
@@ -1050,4 +1056,4 @@
10501056
"ZOOM_TO_FIT": "Zoom To Fit",
10511057
"ZOOM_TO_RESULTS": "Zoom to results",
10521058
"ZOOM_TO_SCENE": "Zoom to scene"
1053-
}
1059+
}

src/assets/i18n/es.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@
126126
"CANNOT_RENAME_PROJECTS_FOR": "No puede cambiar el nombre de los proyectos de",
127127
"CONFIRM_RENAME_MULTIPLE": "¡Sí! Realmente quiero renombrar estos {{projectCount}} proyectos ({{jobCount}} trabajos) a \"{{newName}}\".",
128128
"CONFIRM_RENAME_SINGLE": "¡Sí! Realmente quiero renombrar este 1 proyecto ({{jobCount}} trabajos) a \"{{newName}}\".",
129+
"CONFIRM_REMOVE_MULTIPLE": "¡Sí! Realmente quiero eliminar estos {{projectCount}} proyectos ({{jobCount}} trabajos).",
130+
"CONFIRM_REMOVE_SINGLE": "¡Sí! Realmente quiero eliminar este 1 proyecto ({{jobCount}} trabajos).",
129131
"CENTER_COLUMN_AND_FILES_COLUMN_RIGHT_WILL_POPULATE": "(columna central) y la columna Archivos (derecha) se completarán.",
130132
"CHARACTERS": "caracteres",
131133
"CHART": "Gráfico",
@@ -714,6 +716,8 @@
714716
"REMOVE_FILE_FROM_DOWNLOADS": "Eliminar archivo de las descargas",
715717
"REMOVE_FILE_FROM_QUEUE": "Eliminar archivo de la lista",
716718
"REMOVE_JOB": "Quitar trabajo",
719+
"REMOVE_PROJECT_NAME": "Eliminar nombre del proyecto",
720+
"REMOVE_PROJECT_NAMES": "Eliminar {{count}} nombres de proyecto",
717721
"REMOVE_RED_EYE": "quitar_ojo_rojo",
718722
"REMOVE_SCENE_FILES_FROM_DOWNLOADS": "Eliminar archivos de escena de las descargas",
719723
"REMOVE_SERIES": "Eliminar serie",
@@ -729,6 +733,8 @@
729733
"RENAME_ALL_FAILED": "Error al renombrar {{count}} trabajo(s).",
730734
"RENAME_COMPLETE": "Cambio de nombre completado",
731735
"RENAME_ERROR": "Ocurrió un error al renombrar los trabajos.",
736+
"RENAME_JOB_TO": "Renombrar trabajo a:",
737+
"RENAME_JOBS_TO": "Renombrar {{count}} trabajos a:",
732738
"RENAME_PARTIAL_SUCCESS": "Se renombraron {{success}} trabajo(s). {{failed}} fallaron.",
733739
"RENAME_SUCCESS": "Se renombraron {{count}} trabajo(s) exitosamente.",
734740
"RENAMING_JOBS": "Renombrando trabajos...",
@@ -1051,4 +1057,4 @@
10511057
"ZOOM_TO_FIT": "Acercar para ajustar",
10521058
"ZOOM_TO_RESULTS": "Acercar a los resultados",
10531059
"ZOOM_TO_SCENE": "Acercar a la escena"
1054-
}
1060+
}

0 commit comments

Comments
 (0)