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

Ca 352 prevent modal opening when mandatory objects are missing #204

29 changes: 16 additions & 13 deletions frontend/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
"$schema": "https://inlang.com/schema/inlang-message-format",
"french": "French",
"english": "English",
"addThreat": "New threat",
"addReferenceControl": "New reference control",
"addAppliedControl": "New applied control",
"addAsset": "New asset",
"addRiskAssessment": "New risk assessment",
"addRiskScenario": "New risk scenario",
"addRiskAcceptance": "New risk acceptance",
"addComplianceAssessment": "New compliance assessment",
"addEvidence": "New evidence",
"addDomain": "New domain",
"addProject": "New project",
"addUser": "New user",
"addPolicy": "New policy",
"addThreat": "Add threat",
"addReferenceControl": "Add reference control",
"addAppliedControl": "Add applied control",
"addAsset": "Add asset",
"addRiskAssessment": "Add risk assessment",
"addRiskScenario": "Add risk scenario",
"addRiskAcceptance": "Add risk acceptance",
"addComplianceAssessment": "Add compliance assessment",
"addEvidence": "Add evidence",
"addDomain": "Add domain",
"addProject": "Add project",
"addUser": "Add user",
"addPolicy": "Add policy",
"associatedThreats": "Associated threats",
"associatedReferenceControls": "Associated reference controls",
"associatedAppliedControls": "Associated applied controls",
Expand Down Expand Up @@ -496,6 +496,9 @@
"taintedFormMessage": "Do you want to leave this page? Changes you made may not be saved.",
"riskScenariosStatus": "Risk scenarios status",
"onlineDocs": "Online documentation",
"warning": "Warning",
"missingMandatoyObjects1": "Some mandatory objects to {model} are not created or imported yet",
"missingMandatoyObjects2": "Please add them before proceeding",
"attemptToDeleteOnlyAdminAccountError": "You can't delete the only admin account of your application.",
"attemptToRemoveOnlyAdminUserGroup": "You can't remove the only admin user of the application from the admin user group."
}
6 changes: 6 additions & 0 deletions frontend/messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@
"acceptedAt": "Accepté le",
"rejectedAt": "Rejeté le",
"revokedAt": "Révoqué le",
"submitted": "Soumis",
"rejected": "Rejeté",
"revoked": "Revoqué",
"locale": "Locale",
"defaultLocale": "Locale par défaut",
"annotation": "Annotation",
Expand Down Expand Up @@ -493,6 +496,9 @@
"taintedFormMessage": "Voulez-vous vraiment quitter cette page ? Toutes les données non enregistrées seront perdues.",
"riskScenariosStatus": "Statut des scénarios de risque",
"onlineDocs": "Documentation en ligne",
"warning": "Attention",
"missingMandatoyObjects1": "Des objets obligatoires pour {model} ne sont pas encore créés ou importés",
"missingMandatoyObjects2": "Veuillez les ajouter avant de continuer",
"attemptToDeleteOnlyAdminAccountError": "Vous ne pouvez pas supprimer votre unique compte administrateur de l'application.",
"attemptToRemoveOnlyAdminUserGroup": "Vous ne pouvez pas retirer le seul compte administrateur de l'application du groupe des administrateurs."
}
36 changes: 36 additions & 0 deletions frontend/src/lib/components/Modals/MissingConstraintsModal.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script lang="ts">
// Props
/** Exposes parent props to this component. */
// export let parent: any;

// Stores
import type { ModalStore } from '@skeletonlabs/skeleton';
import { getModalStore } from '@skeletonlabs/skeleton';
import * as m from '$paraglide/messages';
import { localItems, toCamelCase } from '$lib/utils/locales';
import { languageTag } from '$paraglide/runtime';

const modalStore: ModalStore = getModalStore();

// Base Classes
const cBase = 'card p-4 w-modal shadow-xl space-y-4';
const cHeader = 'text-2xl font-bold text-red-600 animate-pulse';
</script>

{#if $modalStore[0]}
{@const value = $modalStore[0].value}
<div class="modal-example-form {cBase}">
<header class={cHeader} data-testid="modal-title">
<i class="fa-solid fa-triangle-exclamation"></i> {$modalStore[0].title ?? '(title missing)'}
</header>
<div>
{#if value}
{m.missingMandatoyObjects1({model: $modalStore[0].body})}:
{#each value as key}
<li class="font-bold">{localItems(languageTag())[toCamelCase(key)]}</li>
{/each}
{m.missingMandatoyObjects2()}.
{/if}
</div>
</div>
{/if}
10 changes: 10 additions & 0 deletions frontend/src/lib/utils/crud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ type GetOptionsParams = {
extra_fields: (string[] | string)[];
};

export function checkConstraints(constraints: { [key: string]: any }, foreignKeys: any) {
const emptyConstraintsList = [];
for (const [key, constraint] of Object.entries(constraints)) {
if (constraint.required && foreignKeys[key])
if (foreignKeys[key].length === 0)
emptyConstraintsList.push(key);
}
return emptyConstraintsList;
}

function getValue(object: {[key: string]: any},keys: string[]) {
if (typeof keys === "string") {
return object[keys];
Expand Down
18 changes: 16 additions & 2 deletions frontend/src/routes/(app)/[model=urlmodel]/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import CreateModal from '$lib/components/Modals/CreateModal.svelte';
import MissingConstraintsModal from '$lib/components/Modals/MissingConstraintsModal.svelte';
import ModelTable from '$lib/components/ModelTable/ModelTable.svelte';
import type {
ModalComponent,
Expand All @@ -11,26 +12,39 @@
import * as m from '$paraglide/messages';
import { localItems, capitalizeFirstLetter } from '$lib/utils/locales';
import { languageTag } from '$paraglide/runtime';
import { checkConstraints } from '$lib/utils/crud';

export let data: PageData;

const modalStore: ModalStore = getModalStore();

function modalCreateForm(): void {
const modalComponent: ModalComponent = {
let modalComponent: ModalComponent = {
ref: CreateModal,
props: {
form: data.createForm,
model: data.model,
debug: false
}
};
const modal: ModalSettings = {
let modal: ModalSettings = {
type: 'component',
component: modalComponent,
// Data
title: localItems(languageTag())['add' + capitalizeFirstLetter(data.model.localName)]
};
if (checkConstraints(data.createForm.constraints, data.model.foreignKeys).length > 0) {
modalComponent = {
ref: MissingConstraintsModal
};
modal = {
type: 'component',
component: modalComponent,
title: m.warning(),
body: localItems(languageTag())['add' + capitalizeFirstLetter(data.model.localName)].toLowerCase(),
value: checkConstraints(data.createForm.constraints, data.model.foreignKeys)
};
}
modalStore.trigger(modal);
}

Expand Down
Loading
Loading