More automatic eslint fixes, update baseline and eslint docs

This commit is contained in:
Julie Lenaerts 2024-12-11 11:32:29 +01:00
parent e8962782ed
commit 16fe07cce7
14 changed files with 591 additions and 418 deletions

View File

@ -13,6 +13,18 @@ Interesting options are:
- ``--quiet`` to only get errors and silence the warnings
- ``--fix`` to have ESLint fix what it can, automatically. This will not fix everything.
Baseline
--------
To allow us the time to fix linting errors/warnings a baseline has been created using the following command
- ``npx eslint-baseline "**/*.{js,vue}"``
The baseline has been commited and the gitlab CI setup to only fail upon new errors/warnings being created.
When fixing errors/warnings manually, please update the baseline.
1. Delete the current baseline file
2. Run the above command locally, this will automatically create a new baseline that should be commited
Rules
-----

View File

@ -1,18 +1,19 @@
import {makeFetch} from "../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
import {PostStoreObjectSignature, StoredObject} from "../../types";
import { makeFetch } from "../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
import { PostStoreObjectSignature, StoredObject } from "../../types";
const algo = 'AES-CBC';
const algo = "AES-CBC";
const URL_POST = '/asyncupload/temp_url/generate/post';
const URL_POST = "/asyncupload/temp_url/generate/post";
const keyDefinition = {
name: algo,
length: 256
length: 256,
};
const createFilename = (): string => {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let text = "";
const possible =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < 7; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
@ -29,14 +30,22 @@ const createFilename = (): string => {
* @returns {Promise<StoredObject>} A Promise that resolves to the newly created StoredObject.
*/
export const fetchNewStoredObject = async (): Promise<StoredObject> => {
return makeFetch("POST", '/api/1.0/doc-store/stored-object/create', null);
}
return makeFetch("POST", "/api/1.0/doc-store/stored-object/create", null);
};
export const uploadVersion = async (uploadFile: ArrayBuffer, storedObject: StoredObject): Promise<string> => {
export const uploadVersion = async (
uploadFile: ArrayBuffer,
storedObject: StoredObject,
): Promise<string> => {
const params = new URLSearchParams();
params.append('expires_delay', "180");
params.append('submit_delay', "180");
const asyncData: PostStoreObjectSignature = await makeFetch("GET", `/api/1.0/doc-store/async-upload/temp_url/${storedObject.uuid}/generate/post` + "?" + params.toString());
params.append("expires_delay", "180");
params.append("submit_delay", "180");
const asyncData: PostStoreObjectSignature = await makeFetch(
"GET",
`/api/1.0/doc-store/async-upload/temp_url/${storedObject.uuid}/generate/post` +
"?" +
params.toString(),
);
const suffix = createFilename();
const filename = asyncData.prefix + suffix;
const formData = new FormData();
@ -50,7 +59,7 @@ export const uploadVersion = async (uploadFile: ArrayBuffer, storedObject: Store
const response = await window.fetch(asyncData.url, {
method: "POST",
body: formData,
})
});
if (!response.ok) {
console.error("Error while sending file to store", response);
@ -58,13 +67,22 @@ export const uploadVersion = async (uploadFile: ArrayBuffer, storedObject: Store
}
return Promise.resolve(filename);
}
};
export const encryptFile = async (originalFile: ArrayBuffer): Promise<[ArrayBuffer, Uint8Array, JsonWebKey]> => {
export const encryptFile = async (
originalFile: ArrayBuffer,
): Promise<[ArrayBuffer, Uint8Array, JsonWebKey]> => {
const iv = crypto.getRandomValues(new Uint8Array(16));
const key = await window.crypto.subtle.generateKey(keyDefinition, true, [ "encrypt", "decrypt" ]);
const exportedKey = await window.crypto.subtle.exportKey('jwk', key);
const encrypted = await window.crypto.subtle.encrypt({ name: algo, iv: iv}, key, originalFile);
const key = await window.crypto.subtle.generateKey(keyDefinition, true, [
"encrypt",
"decrypt",
]);
const exportedKey = await window.crypto.subtle.exportKey("jwk", key);
const encrypted = await window.crypto.subtle.encrypt(
{ name: algo, iv: iv },
key,
originalFile,
);
return Promise.resolve([encrypted, iv, exportedKey]);
};

View File

@ -1,18 +1,22 @@
import {CollectionEventPayload} from "../../../../../ChillMainBundle/Resources/public/module/collection";
import {createApp} from "vue";
import DropFileWidget from "../../vuejs/DropFileWidget/DropFileWidget.vue"
import {StoredObject, StoredObjectVersion} from "../../types";
import {_createI18n} from "../../../../../ChillMainBundle/Resources/public/vuejs/_js/i18n";
import { CollectionEventPayload } from "../../../../../ChillMainBundle/Resources/public/module/collection";
import { createApp } from "vue";
import DropFileWidget from "../../vuejs/DropFileWidget/DropFileWidget.vue";
import { StoredObject, StoredObjectVersion } from "../../types";
import { _createI18n } from "../../../../../ChillMainBundle/Resources/public/vuejs/_js/i18n";
const i18n = _createI18n({});
const startApp = (divElement: HTMLDivElement, collectionEntry: null|HTMLLIElement): void => {
console.log('app started', divElement);
const input_stored_object: HTMLInputElement|null = divElement.querySelector("input[data-stored-object]");
const startApp = (
divElement: HTMLDivElement,
collectionEntry: null | HTMLLIElement,
): void => {
console.log("app started", divElement);
const input_stored_object: HTMLInputElement | null =
divElement.querySelector("input[data-stored-object]");
if (null === input_stored_object) {
throw new Error('input to stored object not found');
throw new Error("input to stored object not found");
}
let existingDoc: StoredObject|null = null;
let existingDoc: StoredObject | null = null;
if (input_stored_object.value !== "") {
existingDoc = JSON.parse(input_stored_object.value);
}
@ -20,69 +24,87 @@ const startApp = (divElement: HTMLDivElement, collectionEntry: null|HTMLLIElemen
divElement.appendChild(app_container);
const app = createApp({
template: '<drop-file-widget :existingDoc="this.$data.existingDoc" :allowRemove="true" @addDocument="this.addDocument" @removeDocument="removeDocument"></drop-file-widget>',
template:
'<drop-file-widget :existingDoc="this.$data.existingDoc" :allowRemove="true" @addDocument="this.addDocument" @removeDocument="removeDocument"></drop-file-widget>',
data(vm) {
return {
existingDoc: existingDoc,
}
};
},
components: {
DropFileWidget,
},
methods: {
addDocument: function({stored_object, stored_object_version}: {stored_object: StoredObject, stored_object_version: StoredObjectVersion}): void {
console.log('object added', stored_object);
console.log('version added', stored_object_version);
addDocument: function ({
stored_object,
stored_object_version,
}: {
stored_object: StoredObject;
stored_object_version: StoredObjectVersion;
}): void {
console.log("object added", stored_object);
console.log("version added", stored_object_version);
this.$data.existingDoc = stored_object;
this.$data.existingDoc.currentVersion = stored_object_version;
input_stored_object.value = JSON.stringify(this.$data.existingDoc);
input_stored_object.value = JSON.stringify(
this.$data.existingDoc,
);
},
removeDocument: function(object: StoredObject): void {
console.log('catch remove document', object);
removeDocument: function (object: StoredObject): void {
console.log("catch remove document", object);
input_stored_object.value = "";
this.$data.existingDoc = undefined;
console.log('collectionEntry', collectionEntry);
console.log("collectionEntry", collectionEntry);
if (null !== collectionEntry) {
console.log('will remove collection');
console.log("will remove collection");
collectionEntry.remove();
}
}
}
},
},
});
app.use(i18n).mount(app_container);
}
window.addEventListener('collection-add-entry', ((e: CustomEvent<CollectionEventPayload>) => {
};
window.addEventListener("collection-add-entry", ((
e: CustomEvent<CollectionEventPayload>,
) => {
const detail = e.detail;
const divElement: null|HTMLDivElement = detail.entry.querySelector('div[data-stored-object]');
const divElement: null | HTMLDivElement = detail.entry.querySelector(
"div[data-stored-object]",
);
if (null === divElement) {
throw new Error('div[data-stored-object] not found');
throw new Error("div[data-stored-object] not found");
}
startApp(divElement, detail.entry);
}) as EventListener);
window.addEventListener('DOMContentLoaded', () => {
const upload_inputs: NodeListOf<HTMLDivElement> = document.querySelectorAll('div[data-stored-object]');
window.addEventListener("DOMContentLoaded", () => {
const upload_inputs: NodeListOf<HTMLDivElement> = document.querySelectorAll(
"div[data-stored-object]",
);
upload_inputs.forEach((input: HTMLDivElement): void => {
// test for a parent to check if this is a collection entry
let collectionEntry: null|HTMLLIElement = null;
let parent = input.parentElement;
console.log('parent', parent);
let collectionEntry: null | HTMLLIElement = null;
const parent = input.parentElement;
console.log("parent", parent);
if (null !== parent) {
let grandParent = parent.parentElement;
console.log('grandParent', grandParent);
const grandParent = parent.parentElement;
console.log("grandParent", grandParent);
if (null !== grandParent) {
if (grandParent.tagName.toLowerCase() === 'li' && grandParent.classList.contains('entry')) {
if (
grandParent.tagName.toLowerCase() === "li" &&
grandParent.classList.contains("entry")
) {
collectionEntry = grandParent as HTMLLIElement;
}
}
}
startApp(input, collectionEntry);
})
});
});
export {}
export {};

View File

@ -1,27 +1,34 @@
import {_createI18n} from "../../../../../ChillMainBundle/Resources/public/vuejs/_js/i18n";
import {createApp} from "vue";
import { _createI18n } from "../../../../../ChillMainBundle/Resources/public/vuejs/_js/i18n";
import { createApp } from "vue";
import DocumentActionButtonsGroup from "../../vuejs/DocumentActionButtonsGroup.vue";
import {StoredObject, StoredObjectStatusChange} from "../../types";
import {defineComponent} from "vue";
import { StoredObject, StoredObjectStatusChange } from "../../types";
import { defineComponent } from "vue";
import DownloadButton from "../../vuejs/StoredObjectButton/DownloadButton.vue";
import ToastPlugin from "vue-toast-notification";
const i18n = _createI18n({});
window.addEventListener('DOMContentLoaded', function (e) {
document.querySelectorAll<HTMLDivElement>('div[data-download-button-single]').forEach((el) => {
const storedObject = JSON.parse(el.dataset.storedObject as string) as StoredObject;
const title = el.dataset.title as string;
const app = createApp({
components: {DownloadButton},
data() {
return {storedObject, title, classes: {btn: true, "btn-outline-primary": true}};
},
template: '<download-button :stored-object="storedObject" :at-version="storedObject.currentVersion" :classes="classes" :filename="title" :direct-download="true"></download-button>',
});
window.addEventListener("DOMContentLoaded", function (e) {
document
.querySelectorAll<HTMLDivElement>("div[data-download-button-single]")
.forEach((el) => {
const storedObject = JSON.parse(
el.dataset.storedObject as string,
) as StoredObject;
const title = el.dataset.title as string;
const app = createApp({
components: { DownloadButton },
data() {
return {
storedObject,
title,
classes: { btn: true, "btn-outline-primary": true },
};
},
template:
'<download-button :stored-object="storedObject" :at-version="storedObject.currentVersion" :classes="classes" :filename="title" :direct-download="true"></download-button>',
});
app.use(i18n).use(ToastPlugin).mount(el);
});
app.use(i18n).use(ToastPlugin).mount(el);
});
});

View File

@ -1,54 +1,73 @@
import {_createI18n} from "../../../../../ChillMainBundle/Resources/public/vuejs/_js/i18n";
import { _createI18n } from "../../../../../ChillMainBundle/Resources/public/vuejs/_js/i18n";
import DocumentActionButtonsGroup from "../../vuejs/DocumentActionButtonsGroup.vue";
import {createApp} from "vue";
import {StoredObject, StoredObjectStatusChange} from "../../types";
import {is_object_ready} from "../../vuejs/StoredObjectButton/helpers";
import { createApp } from "vue";
import { StoredObject, StoredObjectStatusChange } from "../../types";
import { is_object_ready } from "../../vuejs/StoredObjectButton/helpers";
import ToastPlugin from "vue-toast-notification";
const i18n = _createI18n({});
window.addEventListener('DOMContentLoaded', function (e) {
document.querySelectorAll<HTMLDivElement>('div[data-download-buttons]').forEach((el) => {
const app = createApp({
components: {DocumentActionButtonsGroup},
data() {
window.addEventListener("DOMContentLoaded", function (e) {
document
.querySelectorAll<HTMLDivElement>("div[data-download-buttons]")
.forEach((el) => {
const app = createApp({
components: { DocumentActionButtonsGroup },
data() {
const datasets = el.dataset as {
filename: string;
canEdit: string;
storedObject: string;
buttonSmall: string;
davLink: string;
davLinkExpiration: string;
};
const datasets = el.dataset as {
filename: string,
canEdit: string,
storedObject: string,
buttonSmall: string,
davLink: string,
davLinkExpiration: string,
};
const storedObject = JSON.parse(
datasets.storedObject,
) as StoredObject,
filename = datasets.filename,
canEdit = datasets.canEdit === "1",
small = datasets.buttonSmall === "1",
davLink =
"davLink" in datasets && datasets.davLink !== ""
? datasets.davLink
: null,
davLinkExpiration =
"davLinkExpiration" in datasets
? Number.parseInt(datasets.davLinkExpiration)
: null;
return {
storedObject,
filename,
canEdit,
small,
davLink,
davLinkExpiration,
};
},
template:
'<document-action-buttons-group :can-edit="canEdit" :filename="filename" :stored-object="storedObject" :small="small" :dav-link="davLink" :dav-link-expiration="davLinkExpiration" @on-stored-object-status-change="onStoredObjectStatusChange"></document-action-buttons-group>',
methods: {
onStoredObjectStatusChange: function (
newStatus: StoredObjectStatusChange,
): void {
this.$data.storedObject.status = newStatus.status;
this.$data.storedObject.filename = newStatus.filename;
this.$data.storedObject.type = newStatus.type;
const
storedObject = JSON.parse(datasets.storedObject) as StoredObject,
filename = datasets.filename,
canEdit = datasets.canEdit === '1',
small = datasets.buttonSmall === '1',
davLink = 'davLink' in datasets && datasets.davLink !== '' ? datasets.davLink : null,
davLinkExpiration = 'davLinkExpiration' in datasets ? Number.parseInt(datasets.davLinkExpiration) : null
;
// remove eventual div which inform pending status
document
.querySelectorAll(
`[data-docgen-is-pending="${this.$data.storedObject.id}"]`,
)
.forEach(function (el) {
el.remove();
});
},
},
});
return { storedObject, filename, canEdit, small, davLink, davLinkExpiration };
},
template: '<document-action-buttons-group :can-edit="canEdit" :filename="filename" :stored-object="storedObject" :small="small" :dav-link="davLink" :dav-link-expiration="davLinkExpiration" @on-stored-object-status-change="onStoredObjectStatusChange"></document-action-buttons-group>',
methods: {
onStoredObjectStatusChange: function(newStatus: StoredObjectStatusChange): void {
this.$data.storedObject.status = newStatus.status;
this.$data.storedObject.filename = newStatus.filename;
this.$data.storedObject.type = newStatus.type;
// remove eventual div which inform pending status
document.querySelectorAll(`[data-docgen-is-pending="${this.$data.storedObject.id}"]`)
.forEach(function(el) {
el.remove();
});
}
}
});
app.use(i18n).use(ToastPlugin).mount(el);
})
app.use(i18n).use(ToastPlugin).mount(el);
});
});

View File

@ -2,7 +2,7 @@ import {
DateTime,
User,
} from "../../../ChillMainBundle/Resources/public/types";
import {SignedUrlGet} from "./vuejs/StoredObjectButton/helpers";
import { SignedUrlGet } from "./vuejs/StoredObjectButton/helpers";
export type StoredObjectStatus = "empty" | "ready" | "failure" | "pending";
@ -64,23 +64,22 @@ export interface StoredObjectStatusChange {
type: string;
}
export interface StoredObjectVersionWithPointInTime extends StoredObjectVersionPersisted {
export interface StoredObjectVersionWithPointInTime
extends StoredObjectVersionPersisted {
"point-in-times": StoredObjectPointInTime[];
"from-restored": StoredObjectVersionPersisted|null;
"from-restored": StoredObjectVersionPersisted | null;
}
export interface StoredObjectPointInTime {
id: number;
byUser: User | null;
reason: 'keep-before-conversion'|'keep-by-user';
reason: "keep-before-conversion" | "keep-by-user";
}
/**
* Function executed by the WopiEditButton component.
*/
export type WopiEditButtonExecutableBeforeLeaveFunction = {
(): Promise<void>;
};
export type WopiEditButtonExecutableBeforeLeaveFunction = () => Promise<void>;
/**
* Object containing information for performering a POST request to a swift object store
@ -135,7 +134,7 @@ export interface ZoomLevel {
id: number;
zoom: number;
label: {
fr?: string,
nl?: string
fr?: string;
nl?: string;
};
}
}

View File

@ -5,29 +5,29 @@ import App from "./App.vue";
const appMessages = {
fr: {
yes: 'Oui',
are_you_sure: 'Êtes-vous sûr·e?',
you_are_going_to_sign: 'Vous allez signer le document',
signature_confirmation: 'Confirmation de la signature',
sign: 'Signer',
choose_another_signature: 'Choisir une autre zone',
cancel: 'Annuler',
last_sign_zone: 'Zone de signature précédente',
next_sign_zone: 'Zone de signature suivante',
add_sign_zone: 'Ajouter une zone de signature',
click_on_document: 'Cliquer sur le document',
last_zone: 'Zone précédente',
next_zone: 'Zone suivante',
add_zone: 'Ajouter une zone',
another_zone: 'Autre zone',
electronic_signature_in_progress: 'Signature électronique en cours...',
loading: 'Chargement...',
remove_sign_zone: 'Enlever la zone',
return: 'Retour',
see_all_pages: 'Voir toutes les pages',
all_pages: 'Toutes les pages',
}
}
yes: "Oui",
are_you_sure: "Êtes-vous sûr·e?",
you_are_going_to_sign: "Vous allez signer le document",
signature_confirmation: "Confirmation de la signature",
sign: "Signer",
choose_another_signature: "Choisir une autre zone",
cancel: "Annuler",
last_sign_zone: "Zone de signature précédente",
next_sign_zone: "Zone de signature suivante",
add_sign_zone: "Ajouter une zone de signature",
click_on_document: "Cliquer sur le document",
last_zone: "Zone précédente",
next_zone: "Zone suivante",
add_zone: "Ajouter une zone",
another_zone: "Autre zone",
electronic_signature_in_progress: "Signature électronique en cours...",
loading: "Chargement...",
remove_sign_zone: "Enlever la zone",
return: "Retour",
see_all_pages: "Voir toutes les pages",
all_pages: "Toutes les pages",
},
};
const i18n = _createI18n(appMessages);

View File

@ -1,12 +1,33 @@
import {StoredObject, StoredObjectVersionPersisted, StoredObjectVersionWithPointInTime} from "../../../types";
import {fetchResults, makeFetch} from "../../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
import {
StoredObject,
StoredObjectVersionPersisted,
StoredObjectVersionWithPointInTime,
} from "../../../types";
import {
fetchResults,
makeFetch,
} from "../../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
export const get_versions = async (storedObject: StoredObject): Promise<StoredObjectVersionWithPointInTime[]> => {
const versions = await fetchResults<StoredObjectVersionWithPointInTime>(`/api/1.0/doc-store/stored-object/${storedObject.uuid}/versions`);
export const get_versions = async (
storedObject: StoredObject,
): Promise<StoredObjectVersionWithPointInTime[]> => {
const versions = await fetchResults<StoredObjectVersionWithPointInTime>(
`/api/1.0/doc-store/stored-object/${storedObject.uuid}/versions`,
);
return versions.sort((a: StoredObjectVersionWithPointInTime, b: StoredObjectVersionWithPointInTime) => b.version - a.version);
}
return versions.sort(
(
a: StoredObjectVersionWithPointInTime,
b: StoredObjectVersionWithPointInTime,
) => b.version - a.version,
);
};
export const restore_version = async (version: StoredObjectVersionPersisted): Promise<StoredObjectVersionWithPointInTime> => {
return await makeFetch<null, StoredObjectVersionWithPointInTime>("POST", `/api/1.0/doc-store/stored-object/restore-from-version/${version.id}`);
}
export const restore_version = async (
version: StoredObjectVersionPersisted,
): Promise<StoredObjectVersionWithPointInTime> => {
return await makeFetch<null, StoredObjectVersionWithPointInTime>(
"POST",
`/api/1.0/doc-store/stored-object/restore-from-version/${version.id}`,
);
};

View File

@ -1,200 +1,235 @@
import {StoredObject, StoredObjectStatus, StoredObjectStatusChange, StoredObjectVersion} from "../../types";
import {makeFetch} from "../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
import {
StoredObject,
StoredObjectStatus,
StoredObjectStatusChange,
StoredObjectVersion,
} from "../../types";
import { makeFetch } from "../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
const MIMES_EDIT = new Set([
'application/vnd.ms-powerpoint',
'application/vnd.ms-excel',
'application/vnd.oasis.opendocument.text',
'application/vnd.oasis.opendocument.text-flat-xml',
'application/vnd.oasis.opendocument.spreadsheet',
'application/vnd.oasis.opendocument.spreadsheet-flat-xml',
'application/vnd.oasis.opendocument.presentation',
'application/vnd.oasis.opendocument.presentation-flat-xml',
'application/vnd.oasis.opendocument.graphics',
'application/vnd.oasis.opendocument.graphics-flat-xml',
'application/vnd.oasis.opendocument.chart',
'application/msword',
'application/vnd.ms-excel',
'application/vnd.ms-powerpoint',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.ms-word.document.macroEnabled.12',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
'application/vnd.ms-excel.sheet.macroEnabled.12',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
'application/x-dif-document',
'text/spreadsheet',
'text/csv',
'application/x-dbase',
'text/rtf',
'text/plain',
'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
"application/vnd.ms-powerpoint",
"application/vnd.ms-excel",
"application/vnd.oasis.opendocument.text",
"application/vnd.oasis.opendocument.text-flat-xml",
"application/vnd.oasis.opendocument.spreadsheet",
"application/vnd.oasis.opendocument.spreadsheet-flat-xml",
"application/vnd.oasis.opendocument.presentation",
"application/vnd.oasis.opendocument.presentation-flat-xml",
"application/vnd.oasis.opendocument.graphics",
"application/vnd.oasis.opendocument.graphics-flat-xml",
"application/vnd.oasis.opendocument.chart",
"application/msword",
"application/vnd.ms-excel",
"application/vnd.ms-powerpoint",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.ms-word.document.macroEnabled.12",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/vnd.ms-excel.sheet.binary.macroEnabled.12",
"application/vnd.ms-excel.sheet.macroEnabled.12",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"application/vnd.ms-powerpoint.presentation.macroEnabled.12",
"application/x-dif-document",
"text/spreadsheet",
"text/csv",
"application/x-dbase",
"text/rtf",
"text/plain",
"application/vnd.openxmlformats-officedocument.presentationml.slideshow",
]);
const MIMES_VIEW = new Set([
...MIMES_EDIT,
[
'image/svg+xml',
'application/vnd.sun.xml.writer',
'application/vnd.sun.xml.calc',
'application/vnd.sun.xml.impress',
'application/vnd.sun.xml.draw',
'application/vnd.sun.xml.writer.global',
'application/vnd.sun.xml.writer.template',
'application/vnd.sun.xml.calc.template',
'application/vnd.sun.xml.impress.template',
'application/vnd.sun.xml.draw.template',
'application/vnd.oasis.opendocument.text-master',
'application/vnd.oasis.opendocument.text-template',
'application/vnd.oasis.opendocument.text-master-template',
'application/vnd.oasis.opendocument.spreadsheet-template',
'application/vnd.oasis.opendocument.presentation-template',
'application/vnd.oasis.opendocument.graphics-template',
'application/vnd.ms-word.template.macroEnabled.12',
'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'application/vnd.ms-excel.template.macroEnabled.12',
'application/vnd.openxmlformats-officedocument.presentationml.template',
'application/vnd.ms-powerpoint.template.macroEnabled.12',
'application/vnd.wordperfect',
'application/x-aportisdoc',
'application/x-hwp',
'application/vnd.ms-works',
'application/x-mswrite',
'application/vnd.lotus-1-2-3',
'image/cgm',
'image/vnd.dxf',
'image/x-emf',
'image/x-wmf',
'application/coreldraw',
'application/vnd.visio2013',
'application/vnd.visio',
'application/vnd.ms-visio.drawing',
'application/x-mspublisher',
'application/x-sony-bbeb',
'application/x-gnumeric',
'application/macwriteii',
'application/x-iwork-numbers-sffnumbers',
'application/vnd.oasis.opendocument.text-web',
'application/x-pagemaker',
'application/x-fictionbook+xml',
'application/clarisworks',
'image/x-wpg',
'application/x-iwork-pages-sffpages',
'application/x-iwork-keynote-sffkey',
'application/x-abiword',
'image/x-freehand',
'application/vnd.sun.xml.chart',
'application/x-t602',
'image/bmp',
'image/png',
'image/gif',
'image/tiff',
'image/jpg',
'image/jpeg',
'application/pdf',
]
])
...MIMES_EDIT,
[
"image/svg+xml",
"application/vnd.sun.xml.writer",
"application/vnd.sun.xml.calc",
"application/vnd.sun.xml.impress",
"application/vnd.sun.xml.draw",
"application/vnd.sun.xml.writer.global",
"application/vnd.sun.xml.writer.template",
"application/vnd.sun.xml.calc.template",
"application/vnd.sun.xml.impress.template",
"application/vnd.sun.xml.draw.template",
"application/vnd.oasis.opendocument.text-master",
"application/vnd.oasis.opendocument.text-template",
"application/vnd.oasis.opendocument.text-master-template",
"application/vnd.oasis.opendocument.spreadsheet-template",
"application/vnd.oasis.opendocument.presentation-template",
"application/vnd.oasis.opendocument.graphics-template",
"application/vnd.ms-word.template.macroEnabled.12",
"application/vnd.openxmlformats-officedocument.spreadsheetml.template",
"application/vnd.ms-excel.template.macroEnabled.12",
"application/vnd.openxmlformats-officedocument.presentationml.template",
"application/vnd.ms-powerpoint.template.macroEnabled.12",
"application/vnd.wordperfect",
"application/x-aportisdoc",
"application/x-hwp",
"application/vnd.ms-works",
"application/x-mswrite",
"application/vnd.lotus-1-2-3",
"image/cgm",
"image/vnd.dxf",
"image/x-emf",
"image/x-wmf",
"application/coreldraw",
"application/vnd.visio2013",
"application/vnd.visio",
"application/vnd.ms-visio.drawing",
"application/x-mspublisher",
"application/x-sony-bbeb",
"application/x-gnumeric",
"application/macwriteii",
"application/x-iwork-numbers-sffnumbers",
"application/vnd.oasis.opendocument.text-web",
"application/x-pagemaker",
"application/x-fictionbook+xml",
"application/clarisworks",
"image/x-wpg",
"application/x-iwork-pages-sffpages",
"application/x-iwork-keynote-sffkey",
"application/x-abiword",
"image/x-freehand",
"application/vnd.sun.xml.chart",
"application/x-t602",
"image/bmp",
"image/png",
"image/gif",
"image/tiff",
"image/jpg",
"image/jpeg",
"application/pdf",
],
]);
export interface SignedUrlGet {
method: 'GET'|'HEAD',
url: string,
expires: number,
object_name: string,
method: "GET" | "HEAD";
url: string;
expires: number;
object_name: string;
}
function is_extension_editable(mimeType: string): boolean {
return MIMES_EDIT.has(mimeType);
return MIMES_EDIT.has(mimeType);
}
function is_extension_viewable(mimeType: string): boolean {
return MIMES_VIEW.has(mimeType);
return MIMES_VIEW.has(mimeType);
}
function build_convert_link(uuid: string) {
return `/chill/wopi/convert/${uuid}`;
return `/chill/wopi/convert/${uuid}`;
}
function build_download_info_link(storedObject: StoredObject, atVersion: null|StoredObjectVersion): string {
function build_download_info_link(
storedObject: StoredObject,
atVersion: null | StoredObjectVersion,
): string {
const url = `/api/1.0/doc-store/async-upload/temp_url/${storedObject.uuid}/generate/get`;
if (null !== atVersion) {
const params = new URLSearchParams({version: atVersion.filename});
const params = new URLSearchParams({ version: atVersion.filename });
return url + '?' + params.toString();
return url + "?" + params.toString();
}
return url;
}
async function download_info_link(storedObject: StoredObject, atVersion: null|StoredObjectVersion): Promise<SignedUrlGet> {
return makeFetch('GET', build_download_info_link(storedObject, atVersion));
async function download_info_link(
storedObject: StoredObject,
atVersion: null | StoredObjectVersion,
): Promise<SignedUrlGet> {
return makeFetch("GET", build_download_info_link(storedObject, atVersion));
}
function build_wopi_editor_link(uuid: string, returnPath?: string) {
if (returnPath === undefined) {
returnPath = window.location.pathname + window.location.search + window.location.hash;
}
if (returnPath === undefined) {
returnPath =
window.location.pathname +
window.location.search +
window.location.hash;
}
return `/chill/wopi/edit/${uuid}?returnPath=` + encodeURIComponent(returnPath);
return (
`/chill/wopi/edit/${uuid}?returnPath=` + encodeURIComponent(returnPath)
);
}
function download_doc(url: string): Promise<Blob> {
return window.fetch(url).then(r => {
if (r.ok) {
return r.blob()
}
return window.fetch(url).then((r) => {
if (r.ok) {
return r.blob();
}
throw new Error('Could not download document');
});
throw new Error("Could not download document");
});
}
async function download_and_decrypt_doc(storedObject: StoredObject, atVersion: null|StoredObjectVersion): Promise<Blob>
{
const algo = 'AES-CBC';
async function download_and_decrypt_doc(
storedObject: StoredObject,
atVersion: null | StoredObjectVersion,
): Promise<Blob> {
const algo = "AES-CBC";
const atVersionToDownload = atVersion ?? storedObject.currentVersion;
const atVersionToDownload = atVersion ?? storedObject.currentVersion;
if (null === atVersionToDownload) {
throw new Error("no version associated to stored object");
}
// sometimes, the downloadInfo may be embedded into the storedObject
console.log('storedObject', storedObject);
let downloadInfo;
if (typeof storedObject._links !== 'undefined' && typeof storedObject._links.downloadLink !== 'undefined') {
downloadInfo = storedObject._links.downloadLink;
} else {
downloadInfo = await download_info_link(storedObject, atVersionToDownload);
if (null === atVersionToDownload) {
throw new Error("no version associated to stored object");
}
const rawResponse = await window.fetch(downloadInfo.url);
// sometimes, the downloadInfo may be embedded into the storedObject
console.log("storedObject", storedObject);
let downloadInfo;
if (
typeof storedObject._links !== "undefined" &&
typeof storedObject._links.downloadLink !== "undefined"
) {
downloadInfo = storedObject._links.downloadLink;
} else {
downloadInfo = await download_info_link(
storedObject,
atVersionToDownload,
);
}
if (!rawResponse.ok) {
throw new Error("error while downloading raw file " + rawResponse.status + " " + rawResponse.statusText);
}
const rawResponse = await window.fetch(downloadInfo.url);
if (atVersionToDownload.iv.length === 0) {
return rawResponse.blob();
}
if (!rawResponse.ok) {
throw new Error(
"error while downloading raw file " +
rawResponse.status +
" " +
rawResponse.statusText,
);
}
const rawBuffer = await rawResponse.arrayBuffer();
try {
const key = await window.crypto.subtle
.importKey('jwk', atVersionToDownload.keyInfos, { name: algo }, false, ['decrypt']);
const iv = Uint8Array.from(atVersionToDownload.iv);
const decrypted = await window.crypto.subtle
.decrypt({ name: algo, iv: iv }, key, rawBuffer);
if (atVersionToDownload.iv.length === 0) {
return rawResponse.blob();
}
return Promise.resolve(new Blob([decrypted]));
} catch (e) {
console.error('encounter error while keys and decrypt operations');
console.error(e);
const rawBuffer = await rawResponse.arrayBuffer();
try {
const key = await window.crypto.subtle.importKey(
"jwk",
atVersionToDownload.keyInfos,
{ name: algo },
false,
["decrypt"],
);
const iv = Uint8Array.from(atVersionToDownload.iv);
const decrypted = await window.crypto.subtle.decrypt(
{ name: algo, iv: iv },
key,
rawBuffer,
);
throw e;
}
return Promise.resolve(new Blob([decrypted]));
} catch (e) {
console.error("encounter error while keys and decrypt operations");
console.error(e);
throw e;
}
}
/**
@ -203,14 +238,16 @@ async function download_and_decrypt_doc(storedObject: StoredObject, atVersion: n
* If the document is already in a pdf on the server side, the document is retrieved "as is" from the usual
* storage.
*/
async function download_doc_as_pdf(storedObject: StoredObject): Promise<Blob>
{
async function download_doc_as_pdf(storedObject: StoredObject): Promise<Blob> {
if (null === storedObject.currentVersion) {
throw new Error("the stored object does not count any version");
}
if (storedObject.currentVersion?.type === 'application/pdf') {
return download_and_decrypt_doc(storedObject, storedObject.currentVersion);
if (storedObject.currentVersion?.type === "application/pdf") {
return download_and_decrypt_doc(
storedObject,
storedObject.currentVersion,
);
}
const convertLink = build_convert_link(storedObject.uuid);
@ -223,25 +260,27 @@ async function download_doc_as_pdf(storedObject: StoredObject): Promise<Blob>
return response.blob();
}
async function is_object_ready(storedObject: StoredObject): Promise<StoredObjectStatusChange>
{
const new_status_response = await window
.fetch( `/api/1.0/doc-store/stored-object/${storedObject.uuid}/is-ready`);
async function is_object_ready(
storedObject: StoredObject,
): Promise<StoredObjectStatusChange> {
const new_status_response = await window.fetch(
`/api/1.0/doc-store/stored-object/${storedObject.uuid}/is-ready`,
);
if (!new_status_response.ok) {
throw new Error("could not fetch the new status");
throw new Error("could not fetch the new status");
}
return await new_status_response.json();
}
export {
build_convert_link,
build_wopi_editor_link,
download_and_decrypt_doc,
download_doc,
download_doc_as_pdf,
is_extension_editable,
is_extension_viewable,
is_object_ready,
build_convert_link,
build_wopi_editor_link,
download_and_decrypt_doc,
download_doc,
download_doc_as_pdf,
is_extension_editable,
is_extension_viewable,
is_object_ready,
};

View File

@ -9,14 +9,18 @@
*
* @throws {Error} If the related entity ID is undefined.
*/
export const buildLinkCreate = (workflowName: string, relatedEntityClass: string, relatedEntityId: number|undefined): string => {
if (typeof (relatedEntityId) === 'undefined') {
export const buildLinkCreate = (
workflowName: string,
relatedEntityClass: string,
relatedEntityId: number | undefined,
): string => {
if (typeof relatedEntityId === "undefined") {
throw new Error("the related entity id is not set");
}
let params = new URLSearchParams();
params.set('entityClass', relatedEntityClass);
params.set('entityId', relatedEntityId.toString(10));
params.set('workflow', workflowName);
const params = new URLSearchParams();
params.set("entityClass", relatedEntityClass);
params.set("entityId", relatedEntityId.toString(10));
params.set("workflow", workflowName);
return `/fr/main/workflow/create?`+params.toString();
return `/fr/main/workflow/create?` + params.toString();
};

View File

@ -28,11 +28,15 @@
* });
* ```
*/
import './collection.scss';
import "./collection.scss";
declare global {
interface GlobalEventHandlersEventMap {
'show-hide-show': CustomEvent<{id: number, froms: HTMLElement[], container: HTMLElement}>,
"show-hide-show": CustomEvent<{
id: number;
froms: HTMLElement[];
container: HTMLElement;
}>;
}
}
@ -47,27 +51,31 @@ export class CollectionEventPayload {
}
export const handleAdd = (button: any): void => {
let
form_name = button.dataset.collectionAddTarget,
const form_name = button.dataset.collectionAddTarget,
prototype = button.dataset.formPrototype,
collection: HTMLUListElement | null = document.querySelector('ul[data-collection-name="' + form_name + '"]');
collection: HTMLUListElement | null = document.querySelector(
'ul[data-collection-name="' + form_name + '"]',
);
if (collection === null) {
return;
}
let
empty_explain: HTMLLIElement | null = collection.querySelector('li[data-collection-empty-explain]'),
entry = document.createElement('li'),
counter = collection.querySelectorAll('li.entry').length, // Updated counter logic
const empty_explain: HTMLLIElement | null = collection.querySelector(
"li[data-collection-empty-explain]",
),
entry = document.createElement("li"),
counter = collection.querySelectorAll("li.entry").length, // Updated counter logic
content = prototype.replace(/__name__/g, counter.toString()),
event = new CustomEvent('collection-add-entry', {detail: new CollectionEventPayload(collection, entry)});
event = new CustomEvent("collection-add-entry", {
detail: new CollectionEventPayload(collection, entry),
});
console.log(counter)
console.log(content)
console.log(counter);
console.log(content);
entry.innerHTML = content;
entry.classList.add('entry');
entry.classList.add("entry");
if ("collectionRegular" in collection.dataset) {
initializeRemove(collection, entry);
@ -81,7 +89,10 @@ export const handleAdd = (button: any): void => {
window.dispatchEvent(event);
};
const initializeRemove = (collection: HTMLUListElement, entry: HTMLLIElement): void => {
const initializeRemove = (
collection: HTMLUListElement,
entry: HTMLLIElement,
): void => {
const button = buildRemoveButton(collection, entry);
if (null === button) {
return;
@ -89,21 +100,24 @@ const initializeRemove = (collection: HTMLUListElement, entry: HTMLLIElement): v
entry.appendChild(button);
};
export const buildRemoveButton = (collection: HTMLUListElement, entry: HTMLLIElement): HTMLButtonElement|null => {
export const buildRemoveButton = (
collection: HTMLUListElement,
entry: HTMLLIElement,
): HTMLButtonElement | null => {
const button = document.createElement("button"),
isPersisted = entry.dataset.collectionIsPersisted || "",
content = collection.dataset.collectionButtonRemoveLabel || "",
allowDelete = collection.dataset.collectionAllowDelete || "",
event = new CustomEvent("collection-remove-entry", {
detail: new CollectionEventPayload(collection, entry),
});
let
button = document.createElement('button'),
isPersisted = entry.dataset.collectionIsPersisted || '',
content = collection.dataset.collectionButtonRemoveLabel || '',
allowDelete = collection.dataset.collectionAllowDelete || '',
event = new CustomEvent('collection-remove-entry', {detail: new CollectionEventPayload(collection, entry)});
if (allowDelete === '0' && isPersisted === '1') {
if (allowDelete === "0" && isPersisted === "1") {
return null;
}
button.classList.add('btn', 'btn-delete', 'remove-entry');
button.classList.add("btn", "btn-delete", "remove-entry");
button.textContent = content;
button.addEventListener('click', (e: Event) => {
button.addEventListener("click", (e: Event) => {
e.preventDefault();
entry.remove();
collection.dispatchEvent(event);
@ -111,15 +125,18 @@ export const buildRemoveButton = (collection: HTMLUListElement, entry: HTMLLIEle
});
return button;
}
};
const collectionsInit = new Set<string>;
const collectionsInit = new Set<string>();
const buttonsInit = new Set<string>();
const initialize = function (target: Document|Element): void {
let
addButtons: NodeListOf<HTMLButtonElement> = document.querySelectorAll("button[data-collection-add-target]"),
collections: NodeListOf<HTMLUListElement> = document.querySelectorAll("ul[data-collection-regular]");
const initialize = function (target: Document | Element): void {
const addButtons: NodeListOf<HTMLButtonElement> = document.querySelectorAll(
"button[data-collection-add-target]",
),
collections: NodeListOf<HTMLUListElement> = document.querySelectorAll(
"ul[data-collection-regular]",
);
for (let i = 0; i < addButtons.length; i++) {
const addButton = addButtons[i];
@ -128,7 +145,7 @@ const initialize = function (target: Document|Element): void {
continue;
}
buttonsInit.add(uniqid);
addButton.addEventListener('click', (e: Event) => {
addButton.addEventListener("click", (e: Event) => {
e.preventDefault();
handleAdd(e.target);
});
@ -140,7 +157,8 @@ const initialize = function (target: Document|Element): void {
continue;
}
collectionsInit.add(uniqid);
let entries: NodeListOf<HTMLLIElement> = collection.querySelectorAll(':scope > li');
const entries: NodeListOf<HTMLLIElement> =
collection.querySelectorAll(":scope > li");
for (let j = 0; j < entries.length; j++) {
if (entries[j].dataset.collectionEmptyExplain === "1") {
continue;
@ -150,11 +168,20 @@ const initialize = function (target: Document|Element): void {
}
};
window.addEventListener('DOMContentLoaded', () => {
window.addEventListener("DOMContentLoaded", () => {
initialize(document);
});
window.addEventListener('show-hide-show', (event: CustomEvent<{id: number; container: HTMLElement; froms: HTMLElement[]}>) => {
const container = event.detail.container as HTMLElement;
initialize(container);
})
window.addEventListener(
"show-hide-show",
(
event: CustomEvent<{
id: number;
container: HTMLElement;
froms: HTMLElement[];
}>,
) => {
const container = event.detail.container as HTMLElement;
initialize(container);
},
);

View File

@ -64,10 +64,10 @@ export interface UserAssociatedInterface {
id: number;
}
export type TranslatableString = {
export interface TranslatableString {
fr?: string;
nl?: string;
};
}
export interface Postcode {
id: number;
@ -76,10 +76,10 @@ export interface Postcode {
center: Point;
}
export type Point = {
export interface Point {
type: "Point";
coordinates: [lat: number, lon: number];
};
}
export interface Country {
id: number;

View File

@ -1,43 +1,43 @@
import {
Address,
Center,
Civility,
DateTime,
User,
WorkflowAvailable
Address,
Center,
Civility,
DateTime,
User,
WorkflowAvailable,
} from "../../../ChillMainBundle/Resources/public/types";
import {StoredObject} from "../../../ChillDocStoreBundle/Resources/public/types";
import { StoredObject } from "../../../ChillDocStoreBundle/Resources/public/types";
export interface Person {
id: number;
type: "person";
text: string;
textAge: string;
firstName: string;
lastName: string;
current_household_address: Address | null;
birthdate: DateTime | null;
deathdate: DateTime | null;
age: number;
phonenumber: string;
mobilenumber: string;
email: string;
gender: "woman" | "man" | "other";
centers: Center[];
civility: Civility | null;
current_household_id: number;
current_residential_addresses: Address[];
id: number;
type: "person";
text: string;
textAge: string;
firstName: string;
lastName: string;
current_household_address: Address | null;
birthdate: DateTime | null;
deathdate: DateTime | null;
age: number;
phonenumber: string;
mobilenumber: string;
email: string;
gender: "woman" | "man" | "other";
centers: Center[];
civility: Civility | null;
current_household_id: number;
current_residential_addresses: Address[];
}
export interface AccompanyingPeriodWorkEvaluationDocument {
id: number;
type: "accompanying_period_work_evaluation_document"
storedObject: StoredObject;
title: string;
createdAt: DateTime | null;
createdBy: User | null;
updatedAt: DateTime | null;
updatedBy: User | null;
workflows_availables: WorkflowAvailable[];
workflows: object[];
id: number;
type: "accompanying_period_work_evaluation_document";
storedObject: StoredObject;
title: string;
createdAt: DateTime | null;
createdBy: User | null;
updatedAt: DateTime | null;
updatedBy: User | null;
workflows_availables: WorkflowAvailable[];
workflows: object[];
}

View File

@ -1,6 +1,11 @@
import {AccompanyingPeriodWorkEvaluationDocument} from "../../types";
import {makeFetch} from "../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
import { AccompanyingPeriodWorkEvaluationDocument } from "../../types";
import { makeFetch } from "../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
export const duplicate = async (id: number): Promise<AccompanyingPeriodWorkEvaluationDocument> => {
return makeFetch<null, AccompanyingPeriodWorkEvaluationDocument>("POST", `/api/1.0/person/accompanying-course-work-evaluation-document/${id}/duplicate`);
}
export const duplicate = async (
id: number,
): Promise<AccompanyingPeriodWorkEvaluationDocument> => {
return makeFetch<null, AccompanyingPeriodWorkEvaluationDocument>(
"POST",
`/api/1.0/person/accompanying-course-work-evaluation-document/${id}/duplicate`,
);
};