Skip to content

Commit

Permalink
Merge pull request #499 from gordlin/prevent-uuid-overwrite
Browse files Browse the repository at this point in the history
Ban overwriting of UUIDs on new product creation, modify "edit metadata" modal design
  • Loading branch information
szczz authored Jan 20, 2025
2 parents 9c4ab35 + 7f91ccd commit f3f3548
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 55 deletions.
153 changes: 99 additions & 54 deletions src/components/metadata-editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,13 @@
</ul>
</div>
</div>
<!-- If config is loading, display a small spinner. -->
<div
class="inline-flex align-middle ml-1 mb-1"
v-if="checkingUuid && !editExisting"
>
<spinner size="24px" color="#009cd1" class="mx-2 my-auto"></spinner>
</div>
<!-- Load UUID button -->
<!-- Load storyline with the given UUID, if it exists on the server, and also
any history associated with the product that can be found -->
Expand Down Expand Up @@ -451,14 +458,23 @@
<!-- Continue button -->
<!-- Moves you to the editor -->
<div class="ml-auto">
<button
:disabled="loadStatus === 'loading'"
@click="warning === 'none' ? continueToEditor() : $vfm.open(`confirm-uuid-overwrite`)"
class="editor-button editor-forms-button m-0 bg-black text-white"
<div
class="flex justify-end gap-1 items-center"
:class="{ hidden: editExisting && loadStatus !== 'loaded' }"
>
{{ $t('editor.next') }}
</button>
<!-- If config is loading, display a small spinner. -->
<div class="inline-flex align-middle ml-1 mb-1" v-if="loadingIntoEditor">
<spinner size="24px" color="#009cd1" class="mx-2 my-auto"></spinner>
</div>
<button
:disabled="loadingIntoEditor || !uuid || error || loadStatus === 'loading' || checkingUuid"
@click="warning === 'none' ? continueToEditor() : $vfm.open(`confirm-uuid-overwrite`)"
class="editor-button editor-forms-button m-0 bg-black text-white"
>
{{ $t('editor.next') }}
</button>
</div>

<confirmation-modal
:name="`confirm-uuid-overwrite`"
:message="
Expand Down Expand Up @@ -495,35 +511,41 @@
<vue-final-modal
@click="saveMetadata(false)"
modalId="metadata-edit-modal"
content-class="max-h-full overflow-y-auto max-w-xl mx-4 p-7 bg-white border rounded-lg"
content-class="edit-metadata-content max-h-full overflow-y-auto max-w-xl mx-4 p-7 bg-white border rounded-lg"
class="flex justify-center items-center"
>
<div @click.stop class="flex flex-col space-y-2">
<h2 slot="header" class="text-2xl font-bold">{{ $t('editor.editMetadata') }}</h2>
<!-- ENG/FR config toggle -->
<div class="mb-3">
<button
class="editor-button editor-forms-button border border-gray-300"
@click="swapLang()"
tabindex="0"
>
{{ configLang === 'en' ? $t('editor.frenchConfig') : $t('editor.englishConfig') }}
</button>
<div class="sticky top-0 bg-white pt-5 pb-2 mb-2 border-b border-gray-300">
<div class="flex justify-between items-center flex-wrap gap-y-1.5 gap-x-5 mb-2">
<h2 slot="header" class="text-2xl font-bold">{{ $t('editor.editMetadata') }}</h2>
<div class="flex flex-row gap-2">
<!-- ENG/FR config toggle -->
<button
class="editor-button editor-forms-button border border-gray-300"
@click="swapLang()"
tabindex="0"
>
{{
configLang === 'en'
? $t('editor.frenchConfig')
: $t('editor.englishConfig')
}}
</button>
<button
class="editor-button editor-forms-button bg-black text-white hover:bg-gray-800"
@click="saveMetadata(false)"
>
{{ $t('editor.done') }}
</button>
</div>
</div>
</div>
<metadata-content
:metadata="metadata"
@metadata-changed="updateMetadata"
@logo-changed="onFileChange"
@logo-source-changed="onLogoSourceInput"
></metadata-content>
<div class="w-full flex justify-end">
<button
class="editor-button editor-forms-button bg-black text-white hover:bg-gray-800"
@click="saveMetadata(false)"
>
{{ $t('editor.done') }}
</button>
</div>
</div>
</vue-final-modal>
</template>
Expand Down Expand Up @@ -633,9 +655,10 @@ export default class MetadataEditorV extends Vue {
reloadExisting = false;
loadStatus = 'waiting';
checkingUuid = false;
loadingIntoEditor = false;
loadEditor = false;
error = false; // whether an error has occurred
warning: 'none' | 'uuid' | 'rename' = 'none'; // used for duplicate uuid warning
warning: 'none' | 'uuid' | 'rename' | 'blank' = 'none'; // used for duplicate uuid warning
configLang = 'en';
currLang = 'en'; // page language
showDropdown = false;
Expand Down Expand Up @@ -1821,16 +1844,28 @@ export default class MetadataEditorV extends Vue {
}
checkUuid = throttle(300, (rename?: boolean): void => {
if (rename) this.checkingUuid = true;
if (rename || !this.loadExisting) this.checkingUuid = true;
if (!this.loadExisting || rename) {
if (!rename && !this.uuid) {
if (!this.loadExisting) {
this.error = true;
this.warning = 'blank';
}
this.checkingUuid = false;
return;
}
// If renaming, show the loading spinner while we check whether the UUID is taken.
fetch(this.apiUrl + `/check/${rename ? this.changeUuid : this.uuid}`).then((res: Response) => {
if (res.status !== 404) {
this.warning = rename ? 'rename' : 'uuid';
if (!this.loadExisting) {
this.error = true;
}
}
if (rename) this.checkingUuid = false;
if (rename || !this.loadExisting) this.checkingUuid = false;
fetch(this.apiUrl + `/retrieveMessages`)
.then((res: any) => {
Expand Down Expand Up @@ -1935,34 +1970,40 @@ export default class MetadataEditorV extends Vue {
* Called when 'next' button is pressed on metadata page to continue to main editor.
*/
continueToEditor(): void {
if (!this.checkRequiredFields()) {
return;
}
if (this.loadExisting) {
if (this.configs[this.configLang] !== undefined && this.uuid === this.configFileStructure?.uuid) {
this.loadEditor = true;
this.saveMetadata(false);
this.updateEditorPath();
this.loadingIntoEditor = true;
// Needed in order to show the loading spinner at all
// Although it shows, it's still frozen (since app's really just lagging until editor's in)
setTimeout(() => {
if (!this.checkRequiredFields()) {
return;
}
if (this.loadExisting) {
if (this.configs[this.configLang] !== undefined && this.uuid === this.configFileStructure?.uuid) {
this.loadEditor = true;
this.saveMetadata(false);
this.updateEditorPath();
} else {
Message.error(this.$t('editor.editMetadata.message.error.noConfig'));
}
} else if (!this.uuid) {
Message.error(this.$t('editor.warning.mustEnterUuid'));
this.error = true;
} else {
Message.error(this.$t('editor.editMetadata.message.error.noConfig'));
// We have a new product that is going to the main editor route, so its UUID is now locked.
// Therefore, we also lock it in the server so that another user does not create a new product
// with the same UUID until the user's session is in progress.
this.lockStore
.lockStoryline(this.uuid)
.then(() => {
this.generateNewConfig();
})
.catch(() => {
this.error = true;
Message.error(this.$t('editor.editMetadata.message.error.unauthorized'));
});
}
} else if (!this.uuid) {
Message.error(this.$t('editor.warning.mustEnterUuid'));
this.error = true;
} else {
// We have a new product that is going to the main editor route, so its UUID is now locked.
// Therefore, we also lock it in the server so that another user does not create a new product
// with the same UUID until the user's session is in progress.
this.lockStore
.lockStoryline(this.uuid)
.then(() => {
this.generateNewConfig();
})
.catch(() => {
this.error = true;
Message.error(this.$t('editor.editMetadata.message.error.unauthorized'));
});
}
}, 25);
}
/**
Expand Down Expand Up @@ -2161,4 +2202,8 @@ $font-list: 'Segoe UI', system-ui, ui-sans-serif, Tahoma, Geneva, Verdana, sans-
outline-color: #eab308;
}
}
.edit-metadata-content {
padding-top: 0 !important;
}
</style>
3 changes: 2 additions & 1 deletion src/lang/lang.csv
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,12 @@ editor.uuid.required,(required),1,(obligatoire),0
editor.uuid.new,New UUID,1,New UUID,0
editor.warning.mustEnterUuid,You must first enter a UUID.,1,Vous devez d'abord saisir un UUID.,0
editor.warning.retrievalFailed,"Failed to load product, no response from server.",1,"Échec du chargement du produit, aucune réponse du serveur.",0
editor.warning.uuid,UUID already exists. Saving this will overwrite existing product.,1,L’IDUU existe déjà. Enregistrer ce produit écrasera le produit existant.,1
editor.warning.uuid,UUID already exists. Please choose a different one.,1,L’IDUU existe déjà. Veuillez en choisir un autre.,0
editor.warning.uuidNotFound,The requested UUID '{uuid}' does not exist.,1,L'UUID '{uuid}' demandé n'existe pas,0
editor.metadata.uuidInstructions,"Please enter the UUID of an existing storylines product, then click the 'Load' button.",1,"Veuillez saisir l'UUID d'un produit de scénario existant, puis cliquez sur le bouton « Charger ».",0
editor.metadata.newUuidInstructions,"Enter a unique ID for your new storyline. One has been auto-generated for you, but you can also enter your own.",1,"Entrez un identifiant unique pour votre nouveau scénario. Un a été généré automatiquement pour vous, mais vous pouvez également saisir le vôtre.",0
editor.warning.rename,UUID already in use. Please choose a different ID.,1,UUID déjà utilisé. Veuillez choisir un autre identifiant.,0
editor.warning.blank,UUID field cannot be blank. Please enter a unique UUID.,1,Le champ UUID ne peut pas être vide. Veuillez saisir un UUID unique.,0
editor.warning.renameFailed,Failed to rename product.,1,Échec du renommage du produit.,0
editor.changeUuid,Click here to change UUID,1,Cliquez ici pour changer,0
editor.title,Title,1,Titre,1
Expand Down

0 comments on commit f3f3548

Please sign in to comment.