Skip to content

Commit

Permalink
Add import and export ui
Browse files Browse the repository at this point in the history
  • Loading branch information
Dassderdie authored and ClFeSc committed May 29, 2022
1 parent 7d76196 commit 6f16d26
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 3 deletions.
11 changes: 11 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"bootstrap": "^5.1.3",
"bootstrap-icons": "^1.8.1",
"chart.js": "^3.7.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"digital-fuesim-manv-shared": "file:../shared",
"lodash-es": "4.17.21",
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/app/core/api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,15 @@ export class ApiService {
);
}

public async importExercise(exerciseState: ExerciseState) {
return lastValueFrom(
this.httpClient.post<ExerciseIds>(
`${httpOrigin}/api/exercise/${this.exerciseId}`,
exerciseState
)
);
}

public async deleteExercise(trainerId: string) {
return lastValueFrom(
this.httpClient.delete<undefined>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,27 @@
>
Start
</button>
<button (click)="deleteExercise()" class="btn btn-danger ms-3 float-end">
Übung löschen
</button>
<div class="float-end">
<button
(click)="exportExerciseState()"
class="btn btn-outline-primary ms-3"
>
<i class="bi-cloud-download me-2"> </i>
Export
</button>
<label class="btn btn-outline-warning ms-3">
<i class="bi-cloud-upload me-2"> </i>
Import
<input
(input)="importExerciseState($any($event.target).files)"
type="file"
accept="application/json"
class="d-none"
/>
</label>

<button (click)="deleteExercise()" class="btn btn-danger ms-3">
Übung löschen
</button>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { Store } from '@ngrx/store';
import { plainToInstance } from 'class-transformer';
import type { Constructor, ExportImportFile } from 'digital-fuesim-manv-shared';
import { PartialExport, StateExport } from 'digital-fuesim-manv-shared';
import { ApiService } from 'src/app/core/api.service';
import { ConfirmationModalService } from 'src/app/core/confirmation-modal/confirmation-modal.service';
import { MessageService } from 'src/app/core/messages/message.service';
import { saveBlob } from 'src/app/shared/functions/save-blob';
import type { AppState } from 'src/app/state/app.state';
import { selectExerciseStatus } from 'src/app/state/exercise/exercise.selectors';
import { getStateSnapshot } from 'src/app/state/get-state-snapshot';
import { openClientOverviewModal } from '../client-overview/open-client-overview-modal';
import { openExerciseSettingsModal } from '../exercise-settings/open-exercise-settings-modal';
import { openExerciseStatisticsModal } from '../exercise-statistics/open-exercise-statistics-modal';
Expand Down Expand Up @@ -107,4 +112,67 @@ export class TrainerToolbarComponent {
this.router.navigate(['/']);
});
}

public exportExerciseState() {
const blob = new Blob([
// TODO: Allow more export types
JSON.stringify(
new StateExport(
getStateSnapshot(this.store).exercise,
undefined
)
),
]);
saveBlob(
blob,
`exercise-state-${
getStateSnapshot(this.store).exercise.participantId
}.json`
);
}

public async importExerciseState(fileList: FileList) {
try {
const importString = await fileList.item(0)?.text();
if (!importString) {
throw new Error('No file selected');
}
const importPlain = JSON.parse(importString) as ExportImportFile;
const type = importPlain.type;
if (!['complete', 'partial'].includes(type)) {
throw new Error(`Ungültiger Dateityp: \`type === ${type}\``);
}
const importInstance = plainToInstance(
(type === 'complete'
? StateExport
: PartialExport) as Constructor<
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-arguments
PartialExport | StateExport
>,
importPlain
);
switch (importInstance.type) {
case 'complete': {
throw new Error(
'Dieser Typ kann zur Zeit nicht importiert werden.'
);
break;
}
case 'partial': {
throw new Error(
'Dieser Typ kann zur Zeit nicht importiert werden.'
);
break;
}
}
// const exerciseState: ExerciseState = JSON.parse(importString);
// await this.apiService.importExercise(exerciseState);
// location.reload();
} catch (error: unknown) {
this.messageService.postError({
title: 'Fehler beim Importieren der Übung',
error,
});
}
}
}
15 changes: 15 additions & 0 deletions frontend/src/app/shared/functions/save-blob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Saves the blob under the specified fileName
*/
export function saveBlob(blob: Blob, fileName: string) {
// See https://stackoverflow.com/a/19328891
// this is inspired by https://github.com/eligrey/FileSaver.js
const a = document.createElement('a');
a.setAttribute('style', 'display: none');
const url = URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
URL.revokeObjectURL(url);
a.remove();
}
3 changes: 3 additions & 0 deletions shared/src/export-import/file-format/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './base-file';
export * from './partial-export';
export * from './state-export';
1 change: 1 addition & 0 deletions shared/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// this import is needed for `import { Type } from 'class-transformer';` to work
import 'reflect-metadata';

export * from './export-import/file-format';
export * from './models';
export * from './models/utils';
export * from './utils';
Expand Down

0 comments on commit 6f16d26

Please sign in to comment.