Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow partial export #522

Open
wants to merge 15 commits into
base: dev
Choose a base branch
from
Open

Allow partial export #522

wants to merge 15 commits into from

Conversation

ClFeSc
Copy link
Contributor

@ClFeSc ClFeSc commented Sep 16, 2022

This addresses the partial exports as described in #392.

  • Allow exporting a partial export
  • Allow importing a partial export
  • Find a way to migrate partial exports without too much hassle

@ClFeSc ClFeSc added enhancement New feature or request frontend Issues mainly related to the frontend backend Issues mainly related to the backend labels Sep 16, 2022
@ClFeSc ClFeSc self-assigned this Sep 16, 2022
@Dassderdie Dassderdie linked an issue Sep 30, 2022 that may be closed by this pull request
10 tasks
@ClFeSc
Copy link
Contributor Author

ClFeSc commented Dec 26, 2022

* [ ]  Find a way to migrate partial exports without too much hassle

This is currently depending on #581 as I need to run a migration in the reducer (or the frontend) but not the backend.

@ClFeSc ClFeSc marked this pull request as ready for review December 26, 2022 15:27
@ClFeSc
Copy link
Contributor Author

ClFeSc commented Dec 26, 2022

@Dassderdie Apart from the missing call of the migration this should now be ready for review.

@Dassderdie
Copy link
Collaborator

  1. Skimming through the code, it seemed like having a complete and partial StateExport results in more code than just having a StateExport and a TemplateExport, which are completely separate from each other.

  2. In general, only allowing up-to-date imports in the backend and doing the migration in the frontend, could be advantageous.

    • Less strain on the server (DOS)
    • Old migrations can't be used for attacks.
    • The user can be provided with better feedback during the migration (e.g. "Running migration 1 of 11")

@ClFeSc
Copy link
Contributor Author

ClFeSc commented Dec 27, 2022

  1. Skimming through the code, it seemed like having a complete and partial StateExport results in more code than just having a StateExport and a TemplateExport, which are completely separate from each other.

  2. In general, only allowing up-to-date imports in the backend and doing the migration in the frontend, could be advantageous.

    • Less strain on the server (DOS)
    • Old migrations can't be used for attacks.
    • The user can be provided with better feedback during the migration (e.g. "Running migration 1 of 11")

I agree with both points made. However, I'd stick with the current solution for now. The second point depends on #581, and the first point would be a refactoring I'd like to do separately. Maybe we could even disallow migrations for partial imports for now, depending on your plan with #581.

Copy link
Collaborator

@Dassderdie Dassderdie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested it out again. I will do it after these changes are incorporated.

import type { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { PartialExportComponent } from './partial-export-modal/partial-export-modal.component';

export function openPartialExportSelectionModal(ngbModalService: NgbModal) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export function openPartialExportSelectionModal(ngbModalService: NgbModal) {
export function openPartialExportModal(ngbModalService: NgbModal) {

templateUrl: './partial-export-modal.component.html',
styleUrls: ['./partial-export-modal.component.scss'],
})
export class PartialExportComponent {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export class PartialExportComponent {
export class PartialExportModalComponent {

Comment on lines 103 to 108
const importedPlainObject = JSON.parse(importedText) as object;
const importedInstance = plainToInstance(
PartialExport,
importedPlainObject
);
const migratedInstance = migratePartialExport(importedInstance);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this fails the user should get an error message that the import is invalid.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just noticed that this could not fail. However, I don't know whether this is good behavior. When importing an invalid file, the migration function will choose undefined for all three categories, which is valid, just not useful. I'm not quite sure how to proceed there.

Comment on lines 177 to 184
draftState.alarmGroups = Object.fromEntries(
Object.entries(draftState.alarmGroups).map(
([id, alarmGroup]) => {
alarmGroup.alarmGroupVehicles = {};
return [id, alarmGroup];
}
)
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
draftState.alarmGroups = Object.fromEntries(
Object.entries(draftState.alarmGroups).map(
([id, alarmGroup]) => {
alarmGroup.alarmGroupVehicles = {};
return [id, alarmGroup];
}
)
);
for (const alarmGroup of draftState.alarmGroups) {
alarmGroup.alarmGroupVehicles = {};
}

Comment on lines 228 to 236
const templateType = ['mapImageTemplates', 'vehicleTemplates'] as const;
for (const property of templateType) {
const templates = copy[property];
if (templates !== undefined) {
for (const template of templates) {
template.id = uuid();
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const templateType = ['mapImageTemplates', 'vehicleTemplates'] as const;
for (const property of templateType) {
const templates = copy[property];
if (templates !== undefined) {
for (const template of templates) {
template.id = uuid();
}
}
}
const templateTypes = ['mapImageTemplates', 'vehicleTemplates'] as const;
for (const templateType of templateTypes) {
const templates = copy[templateType];
if (templates !== undefined) {
for (const template of templates) {
template.id = uuid();
}
}
}

Comment on lines 33 to 36
const importInstance = plainToInstance(
PartialExport,
this.partialExport
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const importInstance = plainToInstance(
PartialExport,
this.partialExport
);

You should be able to use partialExport directly, as this is just data.

Comment on lines 103 to 108
const importedPlainObject = JSON.parse(importedText) as object;
const importedInstance = plainToInstance(
PartialExport,
importedPlainObject
);
const migratedInstance = migratePartialExport(importedInstance);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const importedPlainObject = JSON.parse(importedText) as object;
const importedInstance = plainToInstance(
PartialExport,
importedPlainObject
);
const migratedInstance = migratePartialExport(importedInstance);
const importedPlainObject = JSON.parse(importedText) as object;
const migratedPartialExport = migratePartialExport(importedPlainObject);
if (!isValid(plainToInstance(
PartialExport,
migratedPartialExport
))) {
throw Error('PartialExport is invalid');
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the moment, you are passing an instance to the modal (instead of a plain object) and, therefore, to the action. I would suspect this to crash, if this instance is later modified in a reducer (e.g., a template gets renamed) as immer.js would find a prototype in the template object.

Remember that all the `.create()-factory-functions were there to not have instances in the state.

FYI: Instead of the factory functions, one could also add a token to those classes in which immer should ignore the prototypes. But having plain objects without prototypes could be more performant (immerjs/immer#941) and maybe less error-prone. #531

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend Issues mainly related to the backend enhancement New feature or request frontend Issues mainly related to the frontend
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Export & Import (full & partial)
2 participants