Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
ae80e35
Add the possibility to save as draft in the database
LenaelleL Oct 23, 2023
63e339a
add JSDOC
LenaelleL Oct 23, 2023
1db5655
do not clear form after save as draft, replace with snackbar
LenaelleL Oct 24, 2023
81c8cae
add button to form header
LenaelleL Oct 24, 2023
5e9b609
Adds a modal when clicking on button
LenaelleL Oct 25, 2023
daab0c4
add draft table with date of creation
LenaelleL Oct 25, 2023
26e2340
Add loading skeleton
LenaelleL Oct 26, 2023
5730c3b
add action buttons
LenaelleL Oct 26, 2023
f606643
see draft records only for current form
LenaelleL Oct 26, 2023
745a84b
add the possibility to delete drafts
LenaelleL Oct 27, 2023
ad8af6e
Add confirm prompt for deletion
LenaelleL Oct 27, 2023
5016e52
add confirm prompt to load draft
LenaelleL Oct 27, 2023
c621e7b
Fill form with data after loading draft record
LenaelleL Oct 27, 2023
44a9a9b
disable save as draft after loading draft
LenaelleL Oct 30, 2023
53ecdee
place queries correctly
LenaelleL Oct 30, 2023
64ba410
add translations
LenaelleL Oct 30, 2023
427ddd0
Add missing JSDoc
LenaelleL Oct 30, 2023
575e66d
overwrite draft record when modifying after first selection
LenaelleL Oct 31, 2023
fade228
add translations for snackbar success messages
LenaelleL Oct 31, 2023
35159a6
Add preview
LenaelleL Oct 31, 2023
154cd3f
Merge branch 'beta' into feat/AB#74319-save-records-as-draft # Please…
estelafs Oct 31, 2023
8d9a8e0
fixed and improvements
estelafs Oct 31, 2023
12944a9
Merge branch 'beta' into feat/AB#74319-save-records-as-draft # Please…
AntoineRelief Nov 6, 2023
3ec43ae
make some updates to the PR
AntoineRelief Nov 6, 2023
2ab3c4c
feat: improvements
estelafs Nov 6, 2023
1596d05
temporary records save as draft and not in local storage
estelafs Nov 7, 2023
884c67f
Merge branch 'beta' into feat/AB#74319-save-records-as-draft # Please…
AntoineRelief Nov 9, 2023
ad41f7d
some linting
AntoineRelief Nov 9, 2023
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions libs/shared/src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,25 @@
"display": {
"submissionMessage": "The form has successfully been submitted."
},
"draftRecords": {
"buttonLoad": "Load draft record",
"confirmModal": {
"confirmDelete": "Do you really want to delete this draft record?",
"confirmLoad": "Do you really want to load this draft record?",
"delete": "Delete this draft",
"load": "Load this draft"
},
"creationDate": "Creation date",
"delete": "Delete this draft",
"load": "Load this draft",
"noDrafts": "No draft available.",
"preview": "Preview this draft",
"previewTitle": "Draft record",
"save": "Save as draft",
"select": "Select draft record",
"successEdit": "Successfully edited draft",
"successSave": "Successfully saved as draft"
},
"layout": {
"delete": {
"confirmationMessage": "Do you confirm the deletion of the layout {{name}}?"
Expand Down
19 changes: 19 additions & 0 deletions libs/shared/src/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,25 @@
"display": {
"submissionMessage": "Le formulaire a été sauvegardé."
},
"draftRecords": {
"buttonLoad": "Charger un brouillon",
"confirmModal": {
"confirmDelete": "Voulez-vous vraiment supprimer ce brouillon ?",
"confirmLoad": "Voulez-vous vraiment charger ce brouillon ?",
"delete": "Supprimer ce brouillon",
"load": "Charger ce brouillon"
},
"creationDate": "Date de création",
"delete": "Supprimer ce brouillon",
"load": "Charger ce brouillon",
"noDrafts": "Aucun enregistrement brouillon disponible",
"preview": "Prévisualiser ce brouillon",
"previewTitle": "Enregistrement brouillon",
"save": "Enregistrer comme brouillon",
"select": "Sélectionner le brouillon",
"successEdit": "Brouillon modifié avec succès",
"successSave": "Enregistré dans les brouillons avec succès"
},
"layout": {
"delete": {
"confirmationMessage": "Voulez-vous vraiment supprimer la mise en page {{name}} ?"
Expand Down
19 changes: 19 additions & 0 deletions libs/shared/src/i18n/test.json
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,25 @@
"display": {
"submissionMessage": "******"
},
"draftRecords": {
"buttonLoad": "******",
"confirmModal": {
"confirmDelete": "******",
"confirmLoad": "******",
"delete": "******",
"load": "******"
},
"creationDate": "******",
"delete": "******",
"load": "******",
"noDrafts": "******",
"preview": "******",
"previewTitle": "******",
"save": "******",
"select": "******",
"successEdit": "******",
"successSave": "******"
},
"layout": {
"delete": {
"confirmationMessage": "****** {{name}} ******"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<ui-dialog [size]="'medium'">
<ng-container ngProjectAs="header">
<h3 class="font-semibold">
{{ 'components.form.draftRecords.select' | translate }}
</h3>
</ng-container>

<ng-container ngProjectAs="content" *ngIf="!loading; else loadingTmpl">
<ng-container *ngIf="!empty; else emptyTmpl">
<!-- Table container -->
<div class="mt-4 overflow-x-hidden shadow-2lg">
<!-- Table scroll container -->
<div class="overflow-x-auto">
<table cdk-table uiTableWrapper [dataSource]="draftRecords">
<ng-container cdkColumnDef="createdAt">
<th uiCellHeader *cdkHeaderCellDef scope="col">
<span class="headerTitle">
{{ 'components.form.draftRecords.creationDate' | translate }}
</span>
</th>
<td
uiCell
*cdkCellDef="let element"
class="!text-gray-900 !font-medium max-w-[30vw]"
>
{{ element.createdAt | sharedDate : 'short' }}
</td>
</ng-container>

<ng-container cdkColumnDef="actions">
<th uiCellHeader *cdkHeaderCellDef scope="col"></th>
<td uiCell class="flex justify-end" *cdkCellDef="let element">
<div class="flex items-center">
<ui-button
[isIcon]="true"
icon="refresh"
variant="primary"
[disabled]="loading"
uiTooltip=" {{
'components.form.draftRecords.load' | translate
}}"
(click)="onClose(element)"
>
</ui-button>
<ui-button
[isIcon]="true"
icon="visibility"
variant="primary"
[disabled]="loading"
uiTooltip=" {{
'components.form.draftRecords.preview' | translate
}}"
(click)="onPreview(element)"
>
</ui-button>
<ui-button
[isIcon]="true"
icon="delete"
variant="danger"
[disabled]="loading"
uiTooltip=" {{
'components.form.draftRecords.delete' | translate
}}"
(click)="onDelete(element)"
>
</ui-button>
</div>
</td>
</ng-container>

<tr cdk-header-row *cdkHeaderRowDef="displayedColumns"></tr>
<tr cdk-row *cdkRowDef="let row; columns: displayedColumns"></tr>
</table>
</div>
</div>
</ng-container>
</ng-container>

<ng-container ngProjectAs="actions">
<ui-button uiDialogClose variant="default">{{
'common.close' | translate
}}</ui-button>
</ng-container>
</ui-dialog>

<!-- Empty indicator -->
<ng-template #emptyTmpl>
<shared-empty
[title]="'components.form.draftRecords.noDrafts' | translate"
></shared-empty>
</ng-template>

<!-- Loading indicator -->
<ng-template #loadingTmpl>
<shared-skeleton-table
class="my-4 mx-0 w-full"
[columns]="displayedColumnsForSkeleton"
>
</shared-skeleton-table>
</ng-template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { DraftRecordListModalComponent } from './draft-record-list-modal.component';

describe('DraftRecordListModalComponent', () => {
let component: DraftRecordListModalComponent;
let fixture: ComponentFixture<DraftRecordListModalComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [DraftRecordListModalComponent],
}).compileComponents();

fixture = TestBed.createComponent(DraftRecordListModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import { SkeletonTableModule } from '../skeleton/skeleton-table/skeleton-table.module';
import { ConfirmService } from '../../services/confirm/confirm.service';
import { DialogRef, DIALOG_DATA } from '@angular/cdk/dialog';
import { DateModule } from '../../pipes/date/date.module';
import { Component, OnInit, Inject } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { GET_DRAFT_RECORDS } from './graphql/queries';
import { CommonModule } from '@angular/common';
import { Dialog } from '@angular/cdk/dialog';
import { Apollo } from 'apollo-angular';
import {
DraftRecordsQueryResponse,
DraftRecord,
} from '../../models/draft-record.model';
import {
TableModule,
DialogModule,
ButtonModule,
TooltipModule,
} from '@oort-front/ui';
import { EmptyModule } from '../ui/empty/empty.module';
import { Form, FormQueryResponse } from '../../models/form.model';
import { FormHelpersService } from '../../services/form-helper/form-helper.service';

/** Dialog data interface */
interface DialogData {
form: string;
}

/**
* Display list of available drafts for form & user, in a modal.
*/
@Component({
standalone: true,
imports: [
CommonModule,
TableModule,
DateModule,
DialogModule,
ButtonModule,
SkeletonTableModule,
TooltipModule,
EmptyModule,
],
selector: 'shared-draft-record-list-modal',
templateUrl: './draft-record-list-modal.component.html',
styleUrls: ['./draft-record-list-modal.component.scss'],
})
export class DraftRecordListModalComponent implements OnInit {
/** Array of available draft records */
public draftRecords: Array<DraftRecord> = new Array<DraftRecord>();
/** Displayed table columns */
public displayedColumns = ['createdAt', 'actions'];
/** Displayed skeleton table columns */
public displayedColumnsForSkeleton = ['createdAt'];
/** Loading indicator */
public loading = true;
/** Current form */
private form!: Form;

/** @returns True if the draft records table is empty */
get empty(): boolean {
return !this.loading && this.draftRecords.length === 0;
}

/**
* Display list of available drafts for form & user, in a modal.
*
* @param confirmService Shared confirm service modal
* @param translate Angular translate service
* @param apollo Apollo service
* @param dialog CDK Dialog service
* @param dialogRef Dialog reference
* @param formHelpersService This is the service that will handle forms.
* @param data Data passed to the dialog, here the formId of the current form
*/
constructor(
private confirmService: ConfirmService,
private translate: TranslateService,
private apollo: Apollo,
public dialog: Dialog,
public dialogRef: DialogRef<DraftRecordListModalComponent>,
public formHelpersService: FormHelpersService,
@Inject(DIALOG_DATA)
public data: DialogData
) {}

ngOnInit(): void {
this.fetchDraftRecords();
}

/**
* Fetches all the draft records associated to the current form
*/
fetchDraftRecords() {
this.apollo
.query<DraftRecordsQueryResponse & FormQueryResponse>({
query: GET_DRAFT_RECORDS,
variables: {
form: this.data.form,
},
})
.pipe()
.subscribe(({ data }) => {
this.form = data.form;
this.draftRecords = data.draftRecords;
this.loading = false;
});
}

/**
* Opens an existing draft record on modal
*
* @param element draft record selected
*/
async onPreview(element: DraftRecord) {
const { DraftRecordModalComponent } = await import(
'../draft-record-modal/draft-record-modal.component'
);
this.dialog.open(DraftRecordModalComponent, {
data: {
form: this.form,
data: element.data,
},
});
}

/**
* Handles the deletion of a specific draft record
*
* @param element Draft record to delete
*/
onDelete(element: DraftRecord) {
const dialogRef = this.confirmService.openConfirmModal({
title: this.translate.instant(
'components.form.draftRecords.confirmModal.delete'
),
content: this.translate.instant(
'components.form.draftRecords.confirmModal.confirmDelete'
),
confirmText: this.translate.instant('components.confirmModal.confirm'),
confirmVariant: 'danger',
});
dialogRef.closed.pipe().subscribe((value) => {
if (value) {
this.loading = true;
const callback = () => {
this.fetchDraftRecords();
};
this.formHelpersService.deleteRecordDraft(
element.id as string,
callback
);
}
});
}

/**
* Closes the modal
*
* @param element Draft record to be returned to form component
*/
onClose(element: DraftRecord): void {
const confirmDialogRef = this.confirmService.openConfirmModal({
title: this.translate.instant(
'components.form.draftRecords.confirmModal.load'
),
content: this.translate.instant(
'components.form.draftRecords.confirmModal.confirmLoad'
),
confirmText: this.translate.instant('components.confirmModal.confirm'),
confirmVariant: 'primary',
});
confirmDialogRef.closed.pipe().subscribe((value) => {
if (value) {
this.dialogRef.close(element as any);
}
});
}
}
Loading