From b262cb007426d25485a837a1e5656c4fa1ecbd41 Mon Sep 17 00:00:00 2001 From: Thijn Date: Wed, 25 Sep 2024 14:02:12 +0200 Subject: [PATCH 01/55] finished register dialog --- .vscode/settings.json | 26 +++ src/modals/Modals.vue | 7 + src/modals/register/DeleteRegister.vue | 97 +++++++++++ src/modals/register/EditRegister.vue | 199 ++++++++++++++++++++++ src/store/modules/navigation.js | 74 ++++----- src/store/modules/register.js | 219 ++++++++++++------------ src/store/modules/schema.js | 220 ++++++++++++------------- src/views/register/RegistersIndex.vue | 2 +- src/views/register/RegistersList.vue | 2 +- 9 files changed, 592 insertions(+), 254 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 src/modals/register/DeleteRegister.vue create mode 100644 src/modals/register/EditRegister.vue diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..fe76d72 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,26 @@ +{ + "files.autoSave": "afterDelay", + "editor.defaultFormatter": "dbaeumer.vscode-eslint", + "editor.formatOnSave": true, + "eslint.format.enable": true, + "cSpell.words": [ + "depubliceren", + "Depubliceren", + "gedepubliceerd", + "Matadata", + "nextcloud", + "opencatalogi", + "organisation", + "Organisation", + "organisations", + "Organisations", + "pinia", + "Toegangs" + ], + "[javascript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + "[css]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, +} diff --git a/src/modals/Modals.vue b/src/modals/Modals.vue index 02ab25c..ce9bf3d 100755 --- a/src/modals/Modals.vue +++ b/src/modals/Modals.vue @@ -1,13 +1,20 @@ diff --git a/src/modals/register/DeleteRegister.vue b/src/modals/register/DeleteRegister.vue new file mode 100644 index 0000000..7963ccb --- /dev/null +++ b/src/modals/register/DeleteRegister.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/src/modals/register/EditRegister.vue b/src/modals/register/EditRegister.vue new file mode 100644 index 0000000..b7a642d --- /dev/null +++ b/src/modals/register/EditRegister.vue @@ -0,0 +1,199 @@ + + + + + diff --git a/src/store/modules/navigation.js b/src/store/modules/navigation.js index f2fd9d5..02ed852 100755 --- a/src/store/modules/navigation.js +++ b/src/store/modules/navigation.js @@ -1,43 +1,41 @@ /* eslint-disable no-console */ import { defineStore } from 'pinia' -export const useNavigationStore = defineStore( - 'ui', { - state: () => ({ - // The currently active menu item, defaults to '' which triggers the dashboard - selected: 'dashboard', - // The currently active modal, managed trough the state to ensure that only one modal can be active at the same time - modal: false, - // The currently active dialog - dialog: false, - // Any data needed in various models, dialogs, views which cannot be transferred through normal means or without writing crappy/excessive code - transferData: null, - }), - actions: { - setSelected(selected) { - this.selected = selected - console.log('Active menu item set to ' + selected) - }, - setSelectedCatalogus(selectedCatalogus) { - this.selectedCatalogus = selectedCatalogus - console.log('Active catalogus menu set to ' + selectedCatalogus) - }, - setModal(modal) { - this.modal = modal - console.log('Active modal set to ' + modal) - }, - setDialog(dialog) { - this.dialog = dialog - console.log('Active dialog set to ' + dialog) - }, - setTransferData(data) { - this.transferData = data - }, - getTransferData() { - const tempData = this.transferData - this.transferData = null - return tempData - }, +export const useNavigationStore = defineStore('ui', { + state: () => ({ + // The currently active menu item, defaults to '' which triggers the dashboard + selected: 'dashboard', + // The currently active modal, managed trough the state to ensure that only one modal can be active at the same time + modal: false, + // The currently active dialog + dialog: false, + // Any data needed in various models, dialogs, views which cannot be transferred through normal means or without writing crappy/excessive code + transferData: null, + }), + actions: { + setSelected(selected) { + this.selected = selected + console.log('Active menu item set to ' + selected) + }, + setSelectedCatalogus(selectedCatalogus) { + this.selectedCatalogus = selectedCatalogus + console.log('Active catalogus menu set to ' + selectedCatalogus) + }, + setModal(modal) { + this.modal = modal + console.log('Active modal set to ' + modal) + }, + setDialog(dialog) { + this.dialog = dialog + console.log('Active dialog set to ' + dialog) + }, + setTransferData(data) { + this.transferData = data + }, + getTransferData() { + const tempData = this.transferData + this.transferData = null + return tempData }, }, -) +}) diff --git a/src/store/modules/register.js b/src/store/modules/register.js index 7a90fd4..420ebcb 100644 --- a/src/store/modules/register.js +++ b/src/store/modules/register.js @@ -2,128 +2,141 @@ import { defineStore } from 'pinia' import { Register } from '../../entities/index.js' -export const useRegisterStore = defineStore( - 'register', { - state: () => ({ - registerItem: false, - registerList: [], - }), - actions: { - setRegisterItem(registerItem) { - this.registerItem = registerItem && new Register(registerItem) - console.log('Active register item set to ' + registerItem) - }, - setRegisterList(registerList) { - this.registerList = registerList.map( - (registerItem) => new Register(registerItem), +export const useRegisterStore = defineStore('register', { + state: () => ({ + registerItem: false, + registerList: [], + }), + actions: { + setRegisterItem(registerItem) { + this.registerItem = registerItem && new Register(registerItem) + console.log('Active register item set to ' + registerItem) + }, + setRegisterList(registerList) { + this.registerList = registerList.map( + (registerItem) => new Register(registerItem), + ) + console.log('Register list set to ' + registerList.length + ' items') + }, + /* istanbul ignore next */ // ignore this for Jest until moved into a service + async refreshRegisterList(search = null) { + // @todo this might belong in a service? + let endpoint = '/index.php/apps/openregister/api/registers' + if (search !== null && search !== '') { + endpoint = endpoint + '?_search=' + search + } + return fetch(endpoint, { + method: 'GET', + }) + .then( + (response) => { + response.json().then( + (data) => { + this.setRegisterList(data.results) + }, + ) + }, ) - console.log('Register list set to ' + registerList.length + ' items') - }, - /* istanbul ignore next */ // ignore this for Jest until moved into a service - async refreshRegisterList(search = null) { - // @todo this might belong in a service? - let endpoint = '/index.php/apps/openregister/api/registers' - if (search !== null && search !== '') { - endpoint = endpoint + '?_search=' + search - } - return fetch(endpoint, { + .catch( + (err) => { + console.error(err) + }, + ) + }, + // New function to get a single register + async getRegister(id) { + const endpoint = `/index.php/apps/openregister/api/registers/${id}` + try { + const response = await fetch(endpoint, { method: 'GET', }) - .then( - (response) => { - response.json().then( - (data) => { - this.setRegisterList(data.results) - }, - ) - }, - ) - .catch( - (err) => { - console.error(err) - }, - ) - }, - // New function to get a single register - async getRegister(id) { - const endpoint = `/index.php/apps/openregister/api/registers/${id}` - try { - const response = await fetch(endpoint, { - method: 'GET', - }) - const data = await response.json() - this.setRegisterItem(data) - return data - } catch (err) { - console.error(err) - throw err - } - }, - // Delete a register - deleteRegister() { - if (!this.registerItem || !this.registerItem.id) { - throw new Error('No register item to delete') - } + const data = await response.json() + this.setRegisterItem(data) + return data + } catch (err) { + console.error(err) + throw err + } + }, + // Delete a register + async deleteRegister(registerItem) { + if (!registerItem.id) { + throw new Error('No register item to delete') + } - console.log('Deleting register...') + console.log('Deleting register...') - const endpoint = `/index.php/apps/openregister/api/registers/${this.registerItem.id}` + const endpoint = `/index.php/apps/openregister/api/registers/${registerItem.id}` - return fetch(endpoint, { + try { + const response = await fetch(endpoint, { method: 'DELETE', }) - .then((response) => { - this.refreshRegisterList() - }) - .catch((err) => { - console.error('Error deleting register:', err) - throw err - }) - }, - // Create or save a register from store - saveRegister() { - if (!this.registerItem) { - throw new Error('No register item to save') + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) } - console.log('Saving register...') + const responseData = await response.json() - const isNewRegister = !this.registerItem.id - const endpoint = isNewRegister - ? '/index.php/apps/openregister/api/registers' - : `/index.php/apps/openregister/api/registers/${this.registerItem.id}` - const method = isNewRegister ? 'POST' : 'PUT' + if (!responseData || typeof responseData !== 'object') { + throw new Error('Invalid response data') + } - // Create a copy of the register item and remove empty properties - const registerToSave = { ...this.registerItem } - Object.keys(registerToSave).forEach(key => { - if (registerToSave[key] === '' || (Array.isArray(registerToSave[key]) && registerToSave[key].length === 0)) { - delete registerToSave[key] - } - }) + this.refreshRegisterList() + + return { response, data: responseData } + } catch (error) { + console.error('Error deleting register:', error) + throw new Error(`Failed to delete register: ${error.message}`) + } + }, + // Create or save a register from store + async saveRegister(registerItem) { + if (!registerItem) { + throw new Error('No register item to save') + } + + console.log('Saving register...') - return fetch( + const isNewRegister = !registerItem.id + const endpoint = isNewRegister + ? '/index.php/apps/openregister/api/registers' + : `/index.php/apps/openregister/api/registers/${registerItem.id}` + const method = isNewRegister ? 'POST' : 'PUT' + + try { + const response = await fetch( endpoint, { method, headers: { 'Content-Type': 'application/json', }, - body: JSON.stringify(registerToSave), - }, + body: JSON.stringify(registerItem), + } ) - .then((response) => response.json()) - .then((data) => { - this.setRegisterItem(data) - console.log('Register saved') - // Refresh the register list - return this.refreshRegisterList() - }) - .catch((err) => { - console.error('Error saving register:', err) - throw err - }) - }, + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } + + const responseData = await response.json() + + if (!responseData || typeof responseData !== 'object') { + throw new Error('Invalid response data') + } + + const data = new Register(responseData) + + this.setRegisterItem(data) + await this.refreshRegisterList() + + return { response, data } + } catch (error) { + console.error('Error saving register:', error) + throw new Error(`Failed to save register: ${error.message}`) + } }, }, -) +}) diff --git a/src/store/modules/schema.js b/src/store/modules/schema.js index 0f39e31..07c8e3c 100644 --- a/src/store/modules/schema.js +++ b/src/store/modules/schema.js @@ -2,128 +2,126 @@ import { defineStore } from 'pinia' import { Schema } from '../../entities/index.js' -export const useSchemaStore = defineStore( - 'schema', { - state: () => ({ - schemaItem: false, - schemaList: [], - }), - actions: { - setSchemaItem(schemaItem) { - this.schemaItem = schemaItem && new Schema(schemaItem) - console.log('Active schema item set to ' + schemaItem) - }, - setSchemaList(schemaList) { - this.schemaList = schemaList.map( - (schemaItem) => new Schema(schemaItem), +export const useSchemaStore = defineStore('schema', { + state: () => ({ + schemaItem: false, + schemaList: [], + }), + actions: { + setSchemaItem(schemaItem) { + this.schemaItem = schemaItem && new Schema(schemaItem) + console.log('Active schema item set to ' + schemaItem) + }, + setSchemaList(schemaList) { + this.schemaList = schemaList.map( + (schemaItem) => new Schema(schemaItem), + ) + console.log('Schema list set to ' + schemaList.length + ' items') + }, + /* istanbul ignore next */ // ignore this for Jest until moved into a service + async refreshSchemaList(search = null) { + // @todo this might belong in a service? + let endpoint = '/index.php/apps/openregister/api/schemas' + if (search !== null && search !== '') { + endpoint = endpoint + '?_search=' + search + } + return fetch(endpoint, { + method: 'GET', + }) + .then( + (response) => { + response.json().then( + (data) => { + this.setSchemaList(data.results) + }, + ) + }, ) - console.log('Schema list set to ' + schemaList.length + ' items') - }, - /* istanbul ignore next */ // ignore this for Jest until moved into a service - async refreshSchemaList(search = null) { - // @todo this might belong in a service? - let endpoint = '/index.php/apps/openregister/api/schemas' - if (search !== null && search !== '') { - endpoint = endpoint + '?_search=' + search - } - return fetch(endpoint, { + .catch( + (err) => { + console.error(err) + }, + ) + }, + // Function to get a single schema + async getSchema(id) { + const endpoint = `/index.php/apps/openregister/api/schemas/${id}` + try { + const response = await fetch(endpoint, { method: 'GET', }) - .then( - (response) => { - response.json().then( - (data) => { - this.setSchemaList(data.results) - }, - ) - }, - ) - .catch( - (err) => { - console.error(err) - }, - ) - }, - // Function to get a single schema - async getSchema(id) { - const endpoint = `/index.php/apps/openregister/api/schemas/${id}` - try { - const response = await fetch(endpoint, { - method: 'GET', - }) - const data = await response.json() - this.setSchemaItem(data) - return data - } catch (err) { - console.error(err) - throw err - } - }, - // Delete a schema - deleteSchema() { - if (!this.schemaItem || !this.schemaItem.id) { - throw new Error('No schema item to delete') - } + const data = await response.json() + this.setSchemaItem(data) + return data + } catch (err) { + console.error(err) + throw err + } + }, + // Delete a schema + deleteSchema() { + if (!this.schemaItem || !this.schemaItem.id) { + throw new Error('No schema item to delete') + } - console.log('Deleting schema...') + console.log('Deleting schema...') - const endpoint = `/index.php/apps/openregister/api/schemas/${this.schemaItem.id}` + const endpoint = `/index.php/apps/openregister/api/schemas/${this.schemaItem.id}` - return fetch(endpoint, { - method: 'DELETE', + return fetch(endpoint, { + method: 'DELETE', + }) + .then((response) => { + this.refreshSchemaList() }) - .then((response) => { - this.refreshSchemaList() - }) - .catch((err) => { - console.error('Error deleting schema:', err) - throw err - }) - }, - // Create or save a schema from store - saveSchema() { - if (!this.schemaItem) { - throw new Error('No schema item to save') - } + .catch((err) => { + console.error('Error deleting schema:', err) + throw err + }) + }, + // Create or save a schema from store + saveSchema() { + if (!this.schemaItem) { + throw new Error('No schema item to save') + } - console.log('Saving schema...') + console.log('Saving schema...') - const isNewSchema = !this.schemaItem.id - const endpoint = isNewSchema - ? '/index.php/apps/openregister/api/schemas' - : `/index.php/apps/openregister/api/schemas/${this.schemaItem.id}` - const method = isNewSchema ? 'POST' : 'PUT' + const isNewSchema = !this.schemaItem.id + const endpoint = isNewSchema + ? '/index.php/apps/openregister/api/schemas' + : `/index.php/apps/openregister/api/schemas/${this.schemaItem.id}` + const method = isNewSchema ? 'POST' : 'PUT' - // Create a copy of the schema item and remove empty properties - const schemaToSave = { ...this.schemaItem } - Object.keys(schemaToSave).forEach(key => { - if (schemaToSave[key] === '' || (Array.isArray(schemaToSave[key]) && schemaToSave[key].length === 0)) { - delete schemaToSave[key] - } - }) + // Create a copy of the schema item and remove empty properties + const schemaToSave = { ...this.schemaItem } + Object.keys(schemaToSave).forEach(key => { + if (schemaToSave[key] === '' || (Array.isArray(schemaToSave[key]) && schemaToSave[key].length === 0)) { + delete schemaToSave[key] + } + }) - return fetch( - endpoint, - { - method, - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(schemaToSave), + return fetch( + endpoint, + { + method, + headers: { + 'Content-Type': 'application/json', }, - ) - .then((response) => response.json()) - .then((data) => { - this.setSchemaItem(data) - console.log('Schema saved') - // Refresh the schema list - return this.refreshSchemaList() - }) - .catch((err) => { - console.error('Error saving schema:', err) - throw err - }) - }, + body: JSON.stringify(schemaToSave), + }, + ) + .then((response) => response.json()) + .then((data) => { + this.setSchemaItem(data) + console.log('Schema saved') + // Refresh the schema list + return this.refreshSchemaList() + }) + .catch((err) => { + console.error('Error saving schema:', err) + throw err + }) }, }, -) +}) diff --git a/src/views/register/RegistersIndex.vue b/src/views/register/RegistersIndex.vue index 325d2b5..99aa432 100644 --- a/src/views/register/RegistersIndex.vue +++ b/src/views/register/RegistersIndex.vue @@ -16,7 +16,7 @@ import { registerStore, navigationStore } from '../../store/store.js' diff --git a/src/views/register/RegistersList.vue b/src/views/register/RegistersList.vue index 87fda81..970d088 100644 --- a/src/views/register/RegistersList.vue +++ b/src/views/register/RegistersList.vue @@ -22,7 +22,7 @@ import { registerStore, navigationStore, searchStore } from '../../store/store.j Ververs - + From 1f4466d3f4647f192d732b041fc15a457a27ae5d Mon Sep 17 00:00:00 2001 From: Remko Date: Wed, 25 Sep 2024 15:23:13 +0200 Subject: [PATCH 02/55] Added small fixes --- css/main.css | 14 +++++++++++--- docker-compose.yml | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 docker-compose.yml diff --git a/css/main.css b/css/main.css index 19ef91a..754ed28 100755 --- a/css/main.css +++ b/css/main.css @@ -5,7 +5,6 @@ } /* Pages */ - .pageHeader { margin-block-start: var(--app-navigation-padding); margin-inline-start: calc( @@ -16,13 +15,14 @@ } /* Lists */ - .listHeader { position: sticky; top: 0; z-index: 1000; background-color: var(--color-main-background); border-bottom: 1px solid var(--color-border); + display: flex; + align-items: center; } .searchField { @@ -37,6 +37,10 @@ } /* Detail pages */ +.detailHeader { + display: flex; + justify-content: space-between; +} .detailContainer { margin-block-start: var(--OC-margin-20); @@ -107,6 +111,11 @@ } /* Modals */ +.modalContent { + margin: var(--OC-margin-50); + text-align: center; +} + .form-group > * { margin-block-end: 10px; } @@ -127,7 +136,6 @@ } /* File drag and drop */ - .filesListDragDropNotice { width: 100%; min-height: 113px; diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..ae87405 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,42 @@ +version: "3.5" +volumes: + nextcloud: + apps: + db: + config: + +services: + db: + image: mariadb:10.6 + restart: always + command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW + volumes: + - db:/var/lib/mysql + environment: + - MYSQL_ROOT_PASSWORD='!ChangeMe!' + - MYSQL_PASSWORD='!ChangeMe!' + - MYSQL_DATABASE=nextcloud + - MYSQL_USER=nextcloud + + nextcloud: + user: root + container_name: nextcloud + image: nextcloud + restart: always + ports: + - 8080:80 + links: + - db + volumes: + - nextcloud:/var/www/html:rw + - ./custom-apps:/var/www/html/custom_apps + - .:/var/www/html/custom_apps/openregister + + environment: + - MYSQL_PASSWORD='!ChangeMe!' + - MYSQL_DATABASE=nextcloud + - MYSQL_USER=nextcloud + - MYSQL_HOST=db + - NEXTCLOUD_ADMIN_USER=admin + - NEXTCLOUD_ADMIN_PASSWORD=admin + - TZ=Europe/Amsterdam From 71563e594169cfa89cfd858ff109e60d06344b55 Mon Sep 17 00:00:00 2001 From: Thijn Date: Wed, 25 Sep 2024 16:04:53 +0200 Subject: [PATCH 03/55] finished schema modals --- src/modals/Modals.vue | 6 ++ src/modals/schema/DeleteSchema.vue | 97 +++++++++++++++++ src/modals/schema/EditSchema.vue | 160 +++++++++++++++++++++++++++++ src/store/modules/register.js | 4 +- src/store/modules/schema.js | 101 ++++++++++-------- src/views/schema/SchemasIndex.vue | 2 +- src/views/schema/SchemasList.vue | 2 +- 7 files changed, 325 insertions(+), 47 deletions(-) create mode 100644 src/modals/schema/DeleteSchema.vue create mode 100644 src/modals/schema/EditSchema.vue diff --git a/src/modals/Modals.vue b/src/modals/Modals.vue index ce9bf3d..07ca45c 100755 --- a/src/modals/Modals.vue +++ b/src/modals/Modals.vue @@ -3,18 +3,24 @@
+ +
diff --git a/src/modals/schema/DeleteSchema.vue b/src/modals/schema/DeleteSchema.vue new file mode 100644 index 0000000..a58d0c1 --- /dev/null +++ b/src/modals/schema/DeleteSchema.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/src/modals/schema/EditSchema.vue b/src/modals/schema/EditSchema.vue new file mode 100644 index 0000000..3eefd7a --- /dev/null +++ b/src/modals/schema/EditSchema.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/src/store/modules/register.js b/src/store/modules/register.js index 420ebcb..d500b6d 100644 --- a/src/store/modules/register.js +++ b/src/store/modules/register.js @@ -114,7 +114,7 @@ export const useRegisterStore = defineStore('register', { 'Content-Type': 'application/json', }, body: JSON.stringify(registerItem), - } + }, ) if (!response.ok) { @@ -130,7 +130,7 @@ export const useRegisterStore = defineStore('register', { const data = new Register(responseData) this.setRegisterItem(data) - await this.refreshRegisterList() + this.refreshRegisterList() return { response, data } } catch (error) { diff --git a/src/store/modules/schema.js b/src/store/modules/schema.js index 07c8e3c..d86c2e6 100644 --- a/src/store/modules/schema.js +++ b/src/store/modules/schema.js @@ -59,69 +59,84 @@ export const useSchemaStore = defineStore('schema', { } }, // Delete a schema - deleteSchema() { - if (!this.schemaItem || !this.schemaItem.id) { + async deleteSchema(schemaItem) { + if (!schemaItem.id) { throw new Error('No schema item to delete') } console.log('Deleting schema...') - const endpoint = `/index.php/apps/openregister/api/schemas/${this.schemaItem.id}` + const endpoint = `/index.php/apps/openregister/api/schemas/${schemaItem.id}` - return fetch(endpoint, { - method: 'DELETE', - }) - .then((response) => { - this.refreshSchemaList() - }) - .catch((err) => { - console.error('Error deleting schema:', err) - throw err + try { + const response = await fetch(endpoint, { + method: 'DELETE', }) + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } + + const responseData = await response.json() + + if (!responseData || typeof responseData !== 'object') { + throw new Error('Invalid response data') + } + + await this.refreshSchemaList() + + return { response, data: responseData } + } catch (error) { + console.error('Error deleting schema:', error) + throw new Error(`Failed to delete schema: ${error.message}`) + } }, // Create or save a schema from store - saveSchema() { - if (!this.schemaItem) { + async saveSchema(schemaItem) { + if (!schemaItem) { throw new Error('No schema item to save') } console.log('Saving schema...') - const isNewSchema = !this.schemaItem.id + const isNewSchema = !schemaItem?.id const endpoint = isNewSchema ? '/index.php/apps/openregister/api/schemas' - : `/index.php/apps/openregister/api/schemas/${this.schemaItem.id}` + : `/index.php/apps/openregister/api/schemas/${schemaItem.id}` const method = isNewSchema ? 'POST' : 'PUT' - // Create a copy of the schema item and remove empty properties - const schemaToSave = { ...this.schemaItem } - Object.keys(schemaToSave).forEach(key => { - if (schemaToSave[key] === '' || (Array.isArray(schemaToSave[key]) && schemaToSave[key].length === 0)) { - delete schemaToSave[key] + try { + const response = await fetch( + endpoint, + { + method, + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(schemaItem), + }, + ) + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) } - }) - return fetch( - endpoint, - { - method, - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(schemaToSave), - }, - ) - .then((response) => response.json()) - .then((data) => { - this.setSchemaItem(data) - console.log('Schema saved') - // Refresh the schema list - return this.refreshSchemaList() - }) - .catch((err) => { - console.error('Error saving schema:', err) - throw err - }) + const responseData = await response.json() + + if (!responseData || typeof responseData !== 'object') { + throw new Error('Invalid response data') + } + + const data = new Schema(responseData) + + this.setSchemaItem(data) + this.refreshSchemaList() + + return { response, data } + } catch (error) { + console.error('Error saving schema:', error) + throw new Error(`Failed to save schema: ${error.message}`) + } }, }, }) diff --git a/src/views/schema/SchemasIndex.vue b/src/views/schema/SchemasIndex.vue index 63c2540..0f43d06 100644 --- a/src/views/schema/SchemasIndex.vue +++ b/src/views/schema/SchemasIndex.vue @@ -16,7 +16,7 @@ import { schemaStore, navigationStore } from '../../store/store.js' diff --git a/src/views/schema/SchemasList.vue b/src/views/schema/SchemasList.vue index aa0fe05..1513979 100644 --- a/src/views/schema/SchemasList.vue +++ b/src/views/schema/SchemasList.vue @@ -22,7 +22,7 @@ import { schemaStore, navigationStore, searchStore } from '../../store/store.js' Ververs
- + From 42d59904754e5b1c7a82ca993d6c5aa61173dd59 Mon Sep 17 00:00:00 2001 From: Thijn Date: Wed, 25 Sep 2024 16:05:06 +0200 Subject: [PATCH 04/55] lint fix --- src/dialogs/Dialogs.vue | 3 +- src/entities/database/database.mock.ts | 38 ++++---- src/entities/database/database.spec.ts | 104 ++++++++++----------- src/entities/database/database.ts | 52 ++++++----- src/entities/database/database.types.ts | 2 +- src/entities/index.js | 1 - src/entities/register/register.mock.ts | 34 +++---- src/entities/register/register.spec.ts | 90 +++++++++--------- src/entities/register/register.ts | 60 ++++++------ src/entities/register/register.types.ts | 2 +- src/entities/register/registration.spec.ts | 1 - src/entities/schema/schema.mock.ts | 58 ++++++------ src/entities/schema/schema.spec.ts | 62 ++++++------ src/entities/schema/schema.ts | 48 +++++----- src/entities/schema/schema.types.ts | 2 +- src/entities/source/source.mock.ts | 16 ++-- src/entities/source/source.spec.ts | 16 ++-- src/entities/source/source.ts | 42 +++++---- src/entities/source/source.types.ts | 2 +- src/sidebars/SideBars.vue | 3 +- src/views/dashboard/DashboardIndex.vue | 2 +- 21 files changed, 321 insertions(+), 317 deletions(-) diff --git a/src/dialogs/Dialogs.vue b/src/dialogs/Dialogs.vue index f404fe9..9f24007 100755 --- a/src/dialogs/Dialogs.vue +++ b/src/dialogs/Dialogs.vue @@ -1,7 +1,6 @@ From 276f6c7e0d20a3948fd148dd56d434cda405ea2c Mon Sep 17 00:00:00 2001 From: Thijn Date: Wed, 25 Sep 2024 16:36:49 +0200 Subject: [PATCH 05/55] finished source modal --- src/modals/Modals.vue | 6 ++ src/modals/source/DeleteSource.vue | 97 ++++++++++++++++++ src/modals/source/EditSource.vue | 152 +++++++++++++++++++++++++++++ src/store/modules/source.js | 78 ++++++++------- 4 files changed, 297 insertions(+), 36 deletions(-) create mode 100644 src/modals/source/DeleteSource.vue create mode 100644 src/modals/source/EditSource.vue diff --git a/src/modals/Modals.vue b/src/modals/Modals.vue index ce9bf3d..bc3af44 100755 --- a/src/modals/Modals.vue +++ b/src/modals/Modals.vue @@ -3,18 +3,24 @@
+ +
diff --git a/src/modals/source/DeleteSource.vue b/src/modals/source/DeleteSource.vue new file mode 100644 index 0000000..39fe887 --- /dev/null +++ b/src/modals/source/DeleteSource.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/src/modals/source/EditSource.vue b/src/modals/source/EditSource.vue new file mode 100644 index 0000000..313c564 --- /dev/null +++ b/src/modals/source/EditSource.vue @@ -0,0 +1,152 @@ + + + + + diff --git a/src/store/modules/source.js b/src/store/modules/source.js index fb8d248..cb1a4ba 100644 --- a/src/store/modules/source.js +++ b/src/store/modules/source.js @@ -60,69 +60,75 @@ export const useSourceStore = defineStore( } }, // Delete a source - deleteSource() { - if (!this.sourceItem || !this.sourceItem.id) { + async deleteSource(sourceItem) { + if (!sourceItem.id) { throw new Error('No source item to delete') } console.log('Deleting source...') - const endpoint = `/index.php/apps/openregister/api/sources/${this.sourceItem.id}` + const endpoint = `/index.php/apps/openregister/api/sources/${sourceItem.id}` - return fetch(endpoint, { + const response = await fetch(endpoint, { method: 'DELETE', }) - .then((response) => { - this.refreshSourceList() - }) - .catch((err) => { - console.error('Error deleting source:', err) - throw err - }) + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } + + const responseData = await response.json() + + if (!responseData || typeof responseData !== 'object') { + throw new Error('Invalid response data') + } + + this.refreshSourceList() + + return { response, data: responseData } + }, // Create or save a source from store - saveSource() { - if (!this.sourceItem) { + async saveSource(sourceItem) { + if (!sourceItem) { throw new Error('No source item to save') } console.log('Saving source...') - const isNewSource = !this.sourceItem.id + const isNewSource = !sourceItem.id const endpoint = isNewSource ? '/index.php/apps/openregister/api/sources' - : `/index.php/apps/openregister/api/sources/${this.sourceItem.id}` + : `/index.php/apps/openregister/api/sources/${sourceItem.id}` const method = isNewSource ? 'POST' : 'PUT' - // Create a copy of the source item and remove empty properties - const sourceToSave = { ...this.sourceItem } - Object.keys(sourceToSave).forEach(key => { - if (sourceToSave[key] === '' || (Array.isArray(sourceToSave[key]) && sourceToSave[key].length === 0)) { - delete sourceToSave[key] - } - }) - - return fetch( + const response = await fetch( endpoint, { method, headers: { 'Content-Type': 'application/json', }, - body: JSON.stringify(sourceToSave), + body: JSON.stringify(sourceItem), }, ) - .then((response) => response.json()) - .then((data) => { - this.setSourceItem(data) - console.log('Source saved') - // Refresh the source list - return this.refreshSourceList() - }) - .catch((err) => { - console.error('Error saving source:', err) - throw err - }) + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } + + const responseData = await response.json() + + if (!responseData || typeof responseData !== 'object') { + throw new Error('Invalid response data') + } + + const data = new Source(responseData) + + this.setSourceItem(data) + await this.refreshSourceList() + + return { response, data } }, }, }, From c35937ddf868a5758d2b8bfe47638e64268ba168 Mon Sep 17 00:00:00 2001 From: Thijn Date: Wed, 25 Sep 2024 16:43:20 +0200 Subject: [PATCH 06/55] small fix --- src/views/source/SourcesIndex.vue | 2 +- src/views/source/SourcesList.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/source/SourcesIndex.vue b/src/views/source/SourcesIndex.vue index 64bf709..e983cbc 100644 --- a/src/views/source/SourcesIndex.vue +++ b/src/views/source/SourcesIndex.vue @@ -16,7 +16,7 @@ import { sourceStore, navigationStore } from '../../store/store.js' diff --git a/src/views/source/SourcesList.vue b/src/views/source/SourcesList.vue index 4b6c686..b37b96f 100644 --- a/src/views/source/SourcesList.vue +++ b/src/views/source/SourcesList.vue @@ -22,7 +22,7 @@ import { sourceStore, navigationStore, searchStore } from '../../store/store.js' Ververs
- + From d460fde38d9dd1f5fcd6f5f6e580ce6d147cd9a8 Mon Sep 17 00:00:00 2001 From: Thijn Date: Thu, 26 Sep 2024 09:55:58 +0200 Subject: [PATCH 07/55] translated to english --- src/modals/source/DeleteSource.vue | 12 ++++++------ src/views/source/SourceDetails.vue | 6 +++--- src/views/source/SourcesIndex.vue | 6 +++--- src/views/source/SourcesList.vue | 12 ++++++------ 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/modals/source/DeleteSource.vue b/src/modals/source/DeleteSource.vue index 39fe887..54fc67a 100644 --- a/src/modals/source/DeleteSource.vue +++ b/src/modals/source/DeleteSource.vue @@ -4,15 +4,15 @@ import { sourceStore, navigationStore } from '../../store/store.js' - Verwijderen + Delete @@ -87,7 +87,7 @@ export default { response.ok && setTimeout(this.closeDialog, 2000) }).catch((error) => { this.success = false - this.error = error.message || 'Er is een fout opgetreden bij het verwijderen van de source' + this.error = error.message || 'An error occurred while deleting the source' }).finally(() => { this.loading = false }) diff --git a/src/views/source/SourceDetails.vue b/src/views/source/SourceDetails.vue index ac7014d..c788f13 100644 --- a/src/views/source/SourceDetails.vue +++ b/src/views/source/SourceDetails.vue @@ -11,7 +11,7 @@ import { sourceStore, navigationStore } from '../../store/store.js' {{ sourceStore.sourceItem.name }} - + @@ -19,13 +19,13 @@ import { sourceStore, navigationStore } from '../../store/store.js' - Bewerken + Edit - Verwijderen + Delete diff --git a/src/views/source/SourcesIndex.vue b/src/views/source/SourcesIndex.vue index e983cbc..9e97f6f 100644 --- a/src/views/source/SourcesIndex.vue +++ b/src/views/source/SourcesIndex.vue @@ -10,14 +10,14 @@ import { sourceStore, navigationStore } from '../../store/store.js' @@ -67,10 +67,10 @@ import { sourceStore, navigationStore, searchStore } from '../../store/store.js' class="loadingIcon" :size="64" appearance="dark" - name="Bronnen aan het laden" /> + name="Loading sources" />
- Er zijn nog geen bronnen gedefinieerd. + No sources have been defined yet.
From 872f5b3438de1cb72a54c7602bac8ab8c0a46126 Mon Sep 17 00:00:00 2001 From: Thijn Date: Thu, 26 Sep 2024 10:37:08 +0200 Subject: [PATCH 08/55] translate to english --- src/modals/schema/DeleteSchema.vue | 12 ++++++------ src/modals/schema/EditSchema.vue | 6 +++--- src/views/schema/SchemaDetails.vue | 6 +++--- src/views/schema/SchemasIndex.vue | 6 +++--- src/views/schema/SchemasList.vue | 12 ++++++------ 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/modals/schema/DeleteSchema.vue b/src/modals/schema/DeleteSchema.vue index a58d0c1..080b078 100644 --- a/src/modals/schema/DeleteSchema.vue +++ b/src/modals/schema/DeleteSchema.vue @@ -4,15 +4,15 @@ import { schemaStore, navigationStore } from '../../store/store.js' - Verwijderen + Delete @@ -87,7 +87,7 @@ export default { response.ok && setTimeout(this.closeDialog, 2000) }).catch((error) => { this.success = false - this.error = error.message || 'Er is een fout opgetreden bij het verwijderen van het schema' + this.error = error.message || 'An error occurred while deleting the schema' }).finally(() => { this.loading = false }) diff --git a/src/modals/schema/EditSchema.vue b/src/modals/schema/EditSchema.vue index 3eefd7a..1d9c7de 100644 --- a/src/modals/schema/EditSchema.vue +++ b/src/modals/schema/EditSchema.vue @@ -8,7 +8,7 @@ import { schemaStore, navigationStore } from '../../store/store.js' size="normal" :can-close="false"> -

Schema succesvol aangepast

+

Schema successfully updated

{{ error }}

@@ -37,7 +37,7 @@ import { schemaStore, navigationStore } from '../../store/store.js' - {{ success ? 'Sluiten' : 'Annuleer' }} + {{ success ? 'Close' : 'Cancel' }} - {{ schemaStore.schemaItem?.id ? 'Opslaan' : 'Aanmaken' }} + {{ schemaStore.schemaItem?.id ? 'Save' : 'Create' }} diff --git a/src/views/schema/SchemaDetails.vue b/src/views/schema/SchemaDetails.vue index 5d327f1..927fc92 100644 --- a/src/views/schema/SchemaDetails.vue +++ b/src/views/schema/SchemaDetails.vue @@ -11,7 +11,7 @@ import { schemaStore, navigationStore } from '../../store/store.js' {{ schemaStore.schemaItem.name }} - + @@ -19,13 +19,13 @@ import { schemaStore, navigationStore } from '../../store/store.js' - Bewerken + Edit
- Verwijderen + Delete diff --git a/src/views/schema/SchemasIndex.vue b/src/views/schema/SchemasIndex.vue index 0f43d06..e8cee54 100644 --- a/src/views/schema/SchemasIndex.vue +++ b/src/views/schema/SchemasIndex.vue @@ -10,14 +10,14 @@ import { schemaStore, navigationStore } from '../../store/store.js' @@ -67,10 +67,10 @@ import { schemaStore, navigationStore, searchStore } from '../../store/store.js' class="loadingIcon" :size="64" appearance="dark" - name="Schema's aan het laden" /> + name="Loading schemas" />
- Er zijn nog geen schema's gedefinieerd. + No schemas have been defined yet.
From ff2541caa80ddcd4fe8cf12611aff6beb74d5e50 Mon Sep 17 00:00:00 2001 From: Thijn Date: Thu, 26 Sep 2024 11:18:28 +0200 Subject: [PATCH 09/55] fixed issue causing console error --- src/modals/source/EditSource.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modals/source/EditSource.vue b/src/modals/source/EditSource.vue index 313c564..48a5677 100644 --- a/src/modals/source/EditSource.vue +++ b/src/modals/source/EditSource.vue @@ -127,7 +127,6 @@ export default { created: '', updated: '', } - this.types.value = null }, async editSource() { this.loading = true From 565012d68bdb946d276191fbca90e4ce4ff79099 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Thu, 26 Sep 2024 12:05:59 +0200 Subject: [PATCH 10/55] Hotfix for id --- lib/Migration/Version1Date20240924200009.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Migration/Version1Date20240924200009.php b/lib/Migration/Version1Date20240924200009.php index 04c20d4..0d950fd 100755 --- a/lib/Migration/Version1Date20240924200009.php +++ b/lib/Migration/Version1Date20240924200009.php @@ -40,7 +40,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt if (!$schema->hasTable('openregister_sources')) { $table = $schema->createTable('openregister_sources'); - $table->addColumn('id', Types::STRING, ['notnull' => true, 'length' => 64]); + $table->addColumn('id', Types::BIGINT, ['autoincrement' => true, 'notnull' => true]); $table->addColumn('title', Types::STRING, ['notnull' => true, 'length' => 255]); $table->addColumn('description', Types::TEXT, ['notnull' => false]); $table->addColumn('database_url', Types::STRING, ['notnull' => true, 'length' => 255]); @@ -74,7 +74,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt if (!$schema->hasTable('openregister_registers')) { $table = $schema->createTable('openregister_registers'); - $table->addColumn('id', Types::STRING, ['notnull' => true, 'length' => 64]); + $table->addColumn('id', Types::BIGINT, ['autoincrement' => true, 'notnull' => true]); $table->addColumn('title', Types::STRING, ['notnull' => true, 'length' => 255]); $table->addColumn('description', Types::TEXT, ['notnull' => false]); $table->addColumn('schemas', Types::JSON, ['notnull' => false]); From b5c99929128a5d48d57167113cb5b6fba4831d82 Mon Sep 17 00:00:00 2001 From: Thijn Date: Thu, 26 Sep 2024 12:10:59 +0200 Subject: [PATCH 11/55] fixed php issues --- lib/Db/Register.php | 2 -- lib/Db/Schema.php | 1 - lib/Db/Source.php | 2 -- 3 files changed, 5 deletions(-) diff --git a/lib/Db/Register.php b/lib/Db/Register.php index 7e4a99d..0f93c77 100644 --- a/lib/Db/Register.php +++ b/lib/Db/Register.php @@ -8,7 +8,6 @@ class Register extends Entity implements JsonSerializable { - protected ?string $id = null; protected ?string $title = null; protected ?string $description = null; protected ?array $schemas = null; @@ -18,7 +17,6 @@ class Register extends Entity implements JsonSerializable protected ?DateTime $created = null; public function __construct() { - $this->addType('id', 'string'); $this->addType('title', 'title'); $this->addType('description', 'string'); $this->addType('schemas', 'array'); diff --git a/lib/Db/Schema.php b/lib/Db/Schema.php index fae5121..c018748 100644 --- a/lib/Db/Schema.php +++ b/lib/Db/Schema.php @@ -8,7 +8,6 @@ class Schema extends Entity implements JsonSerializable { - protected ?string $title = null; protected ?string $version = null; protected ?string $description = null; protected ?string $summary = null; diff --git a/lib/Db/Source.php b/lib/Db/Source.php index 2bd9693..1c63001 100644 --- a/lib/Db/Source.php +++ b/lib/Db/Source.php @@ -8,7 +8,6 @@ class Source extends Entity implements JsonSerializable { - protected ?string $id = null; protected ?string $name = null; protected ?string $description = null; protected ?string $databaseUrl = null; @@ -17,7 +16,6 @@ class Source extends Entity implements JsonSerializable protected ?DateTime $created = null; public function __construct() { - $this->addType('id', 'string'); $this->addType('title', 'string'); $this->addType('description', 'string'); $this->addType('databaseUrl', 'string'); From f20890c515d0602fffbbdcf91a78668ee685db5c Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Thu, 26 Sep 2024 13:16:13 +0200 Subject: [PATCH 12/55] title hydration hotfix --- lib/Db/Register.php | 39 ++++++++++++++++++++++++++++----------- lib/Db/Schema.php | 7 ++++++- lib/Db/Source.php | 27 +++++++++++++++++++++------ 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/lib/Db/Register.php b/lib/Db/Register.php index 7e4a99d..68ad102 100644 --- a/lib/Db/Register.php +++ b/lib/Db/Register.php @@ -8,41 +8,58 @@ class Register extends Entity implements JsonSerializable { - protected ?string $id = null; protected ?string $title = null; protected ?string $description = null; - protected ?array $schemas = null; + protected ?array $schemas = []; protected ?string $source = null; protected ?string $tablePrefix = null; protected ?DateTime $updated = null; protected ?DateTime $created = null; public function __construct() { - $this->addType('id', 'string'); - $this->addType('title', 'title'); - $this->addType('description', 'string'); - $this->addType('schemas', 'array'); - $this->addType('source', 'string'); - $this->addType('tablePrefix', 'string'); - $this->addType('updated', 'datetime'); - $this->addType('created', 'datetime'); + $this->addType(fieldName: 'title', type: 'string'); + $this->addType(fieldName: 'description', type: 'string'); + $this->addType(fieldName: 'properties', type: 'json'); + $this->addType(fieldName: 'source', type: 'string'); + $this->addType(fieldName: 'tablePrefix', type: 'string'); + $this->addType(fieldName:'updated', type: 'datetime'); + $this->addType(fieldName:'created', type: 'datetime'); + } + + public function getJsonFields(): array + { + return array_keys( + array_filter($this->getFieldTypes(), function ($field) { + return $field === 'json'; + }) + ); } public function hydrate(array $object): self { + $jsonFields = $this->getJsonFields(); + + if(isset($object['metadata']) === false) { + $object['metadata'] = []; + } + foreach($object as $key => $value) { + if (in_array($key, $jsonFields) === true && $value === []) { + $value = null; + } + $method = 'set'.ucfirst($key); try { $this->$method($value); } catch (\Exception $exception) { - // Error handling can be added here } } return $this; } + public function jsonSerialize(): array { return [ diff --git a/lib/Db/Schema.php b/lib/Db/Schema.php index fae5121..e5fc470 100644 --- a/lib/Db/Schema.php +++ b/lib/Db/Schema.php @@ -20,13 +20,13 @@ class Schema extends Entity implements JsonSerializable protected ?DateTime $created = null; public function __construct() { - $this->addType(fieldName: 'archive', type: 'json'); $this->addType(fieldName: 'title', type: 'string'); $this->addType(fieldName: 'version', type: 'string'); $this->addType(fieldName: 'description', type: 'string'); $this->addType(fieldName: 'summary', type: 'string'); $this->addType(fieldName: 'required', type: 'json'); $this->addType(fieldName: 'properties', type: 'json'); + $this->addType(fieldName: 'archive', type: 'json'); $this->addType(fieldName: 'source', type: 'string'); $this->addType(fieldName:'updated', type: 'datetime'); $this->addType(fieldName:'created', type: 'datetime'); @@ -45,6 +45,10 @@ public function hydrate(array $object): self { $jsonFields = $this->getJsonFields(); + if(isset($object['metadata']) === false) { + $object['metadata'] = []; + } + foreach($object as $key => $value) { if (in_array($key, $jsonFields) === true && $value === []) { $value = null; @@ -61,6 +65,7 @@ public function hydrate(array $object): self return $this; } + public function jsonSerialize(): array { $properties = []; diff --git a/lib/Db/Source.php b/lib/Db/Source.php index 2bd9693..017285b 100644 --- a/lib/Db/Source.php +++ b/lib/Db/Source.php @@ -8,8 +8,7 @@ class Source extends Entity implements JsonSerializable { - protected ?string $id = null; - protected ?string $name = null; + protected ?string $title = null; protected ?string $description = null; protected ?string $databaseUrl = null; protected ?string $type = null; @@ -17,8 +16,7 @@ class Source extends Entity implements JsonSerializable protected ?DateTime $created = null; public function __construct() { - $this->addType('id', 'string'); - $this->addType('title', 'string'); + $this->addType(fieldName: 'title', type: 'string'); $this->addType('description', 'string'); $this->addType('databaseUrl', 'string'); $this->addType('type', 'string'); @@ -26,21 +24,38 @@ public function __construct() { $this->addType('created', 'datetime'); } + public function getJsonFields(): array + { + return array_keys( + array_filter($this->getFieldTypes(), function ($field) { + return $field === 'json'; + }) + ); + } + public function hydrate(array $object): self { + $jsonFields = $this->getJsonFields(); + + if(isset($object['metadata']) === false) { + $object['metadata'] = []; + } + foreach($object as $key => $value) { + if (in_array($key, $jsonFields) === true && $value === []) { + $value = null; + } + $method = 'set'.ucfirst($key); try { $this->$method($value); } catch (\Exception $exception) { - // Error handling can be added here } } return $this; } - public function jsonSerialize(): array { return [ From cc125a986894abab48ddceb82d40879b6ee0b951 Mon Sep 17 00:00:00 2001 From: Thijn Date: Thu, 26 Sep 2024 13:17:43 +0200 Subject: [PATCH 13/55] fixed more php issues thanks ruben --- lib/Controller/RegistersController.php | 2 +- lib/Controller/SchemasController.php | 2 +- lib/Controller/SourcesController.php | 2 +- lib/Db/Register.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Controller/RegistersController.php b/lib/Controller/RegistersController.php index 58270c1..13b27ba 100644 --- a/lib/Controller/RegistersController.php +++ b/lib/Controller/RegistersController.php @@ -63,7 +63,7 @@ public function page(): TemplateResponse public function index(ObjectService $objectService, SearchService $searchService): JSONResponse { $filters = $this->request->getParams(); - $fieldsToSearch = ['name', 'description']; + $fieldsToSearch = ['title', 'description']; $searchParams = $searchService->createMySQLSearchParams(filters: $filters); $searchConditions = $searchService->createMySQLSearchConditions(filters: $filters, fieldsToSearch: $fieldsToSearch); diff --git a/lib/Controller/SchemasController.php b/lib/Controller/SchemasController.php index 127e717..7f7badf 100644 --- a/lib/Controller/SchemasController.php +++ b/lib/Controller/SchemasController.php @@ -63,7 +63,7 @@ public function page(): TemplateResponse public function index(ObjectService $objectService, SearchService $searchService): JSONResponse { $filters = $this->request->getParams(); - $fieldsToSearch = ['name', 'description']; + $fieldsToSearch = ['title', 'description']; $searchParams = $searchService->createMySQLSearchParams(filters: $filters); $searchConditions = $searchService->createMySQLSearchConditions(filters: $filters, fieldsToSearch: $fieldsToSearch); diff --git a/lib/Controller/SourcesController.php b/lib/Controller/SourcesController.php index 4b10ae7..bc98c2d 100644 --- a/lib/Controller/SourcesController.php +++ b/lib/Controller/SourcesController.php @@ -63,7 +63,7 @@ public function page(): TemplateResponse public function index(ObjectService $objectService, SearchService $searchService): JSONResponse { $filters = $this->request->getParams(); - $fieldsToSearch = ['name', 'description']; + $fieldsToSearch = ['title', 'description']; $searchParams = $searchService->createMySQLSearchParams(filters: $filters); $searchConditions = $searchService->createMySQLSearchConditions(filters: $filters, fieldsToSearch: $fieldsToSearch); diff --git a/lib/Db/Register.php b/lib/Db/Register.php index 0f93c77..232fbca 100644 --- a/lib/Db/Register.php +++ b/lib/Db/Register.php @@ -17,7 +17,7 @@ class Register extends Entity implements JsonSerializable protected ?DateTime $created = null; public function __construct() { - $this->addType('title', 'title'); + $this->addType('title', 'string'); $this->addType('description', 'string'); $this->addType('schemas', 'array'); $this->addType('source', 'string'); From 5a65caf8717143be35effafd5fedcf8854f14ced Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Thu, 26 Sep 2024 13:47:43 +0200 Subject: [PATCH 14/55] Registers hotfixes --- lib/Controller/RegistersController.php | 52 +++++++++++++------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/lib/Controller/RegistersController.php b/lib/Controller/RegistersController.php index 58270c1..782ed80 100644 --- a/lib/Controller/RegistersController.php +++ b/lib/Controller/RegistersController.php @@ -4,8 +4,8 @@ use OCA\OpenRegister\Service\ObjectService; use OCA\OpenRegister\Service\SearchService; -use OCA\OpenRegister\Db\Source; -use OCA\OpenRegister\Db\SourceMapper; +use OCA\OpenRegister\Db\Register; +use OCA\OpenRegister\Db\RegisterMapper; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\JSONResponse; @@ -15,7 +15,7 @@ class RegistersController extends Controller { /** - * Constructor for the SourcesController + * Constructor for the RegistersController * * @param string $appName The name of the app * @param IRequest $request The request object @@ -25,7 +25,7 @@ public function __construct( $appName, IRequest $request, private readonly IAppConfig $config, - private readonly SourceMapper $sourceMapper + private readonly RegisterMapper $registerMapper ) { parent::__construct($appName, $request); @@ -51,14 +51,14 @@ public function page(): TemplateResponse } /** - * Retrieves a list of all sources + * Retrieves a list of all registers * - * This method returns a JSON response containing an array of all sources in the system. + * This method returns a JSON response containing an array of all registers in the system. * * @NoAdminRequired * @NoCSRFRequired * - * @return JSONResponse A JSON response containing the list of sources + * @return JSONResponse A JSON response containing the list of registers */ public function index(ObjectService $objectService, SearchService $searchService): JSONResponse { @@ -69,38 +69,38 @@ public function index(ObjectService $objectService, SearchService $searchService $searchConditions = $searchService->createMySQLSearchConditions(filters: $filters, fieldsToSearch: $fieldsToSearch); $filters = $searchService->unsetSpecialQueryParams(filters: $filters); - return new JSONResponse(['results' => $this->sourceMapper->findAll(limit: null, offset: null, filters: $filters, searchConditions: $searchConditions, searchParams: $searchParams)]); + return new JSONResponse(['results' => $this->registerMapper->findAll(limit: null, offset: null, filters: $filters, searchConditions: $searchConditions, searchParams: $searchParams)]); } /** - * Retrieves a single source by its ID + * Retrieves a single register by its ID * - * This method returns a JSON response containing the details of a specific source. + * This method returns a JSON response containing the details of a specific register. * * @NoAdminRequired * @NoCSRFRequired * - * @param string $id The ID of the source to retrieve - * @return JSONResponse A JSON response containing the source details + * @param string $id The ID of the register to retrieve + * @return JSONResponse A JSON response containing the register details */ public function show(string $id): JSONResponse { try { - return new JSONResponse($this->sourceMapper->find(id: (int) $id)); + return new JSONResponse($this->registerMapper->find(id: (int) $id)); } catch (DoesNotExistException $exception) { return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404); } } /** - * Creates a new source + * Creates a new register * - * This method creates a new source based on POST data. + * This method creates a new register based on POST data. * * @NoAdminRequired * @NoCSRFRequired * - * @return JSONResponse A JSON response containing the created source + * @return JSONResponse A JSON response containing the created register */ public function create(): JSONResponse { @@ -116,19 +116,19 @@ public function create(): JSONResponse unset($data['id']); } - return new JSONResponse($this->sourceMapper->createFromArray(object: $data)); + return new JSONResponse($this->registerMapper->createFromArray(object: $data)); } /** - * Updates an existing source + * Updates an existing register * - * This method updates an existing source based on its ID. + * This method updates an existing register based on its ID. * * @NoAdminRequired * @NoCSRFRequired * - * @param string $id The ID of the source to update - * @return JSONResponse A JSON response containing the updated source details + * @param string $id The ID of the register to update + * @return JSONResponse A JSON response containing the updated register details */ public function update(int $id): JSONResponse { @@ -142,23 +142,23 @@ public function update(int $id): JSONResponse if (isset($data['id'])) { unset($data['id']); } - return new JSONResponse($this->sourceMapper->updateFromArray(id: (int) $id, object: $data)); + return new JSONResponse($this->registerMapper->updateFromArray(id: (int) $id, object: $data)); } /** - * Deletes a source + * Deletes a register * - * This method deletes a source based on its ID. + * This method deletes a register based on its ID. * * @NoAdminRequired * @NoCSRFRequired * - * @param string $id The ID of the source to delete + * @param string $id The ID of the register to delete * @return JSONResponse An empty JSON response */ public function destroy(int $id): JSONResponse { - $this->sourceMapper->delete($this->sourceMapper->find((int) $id)); + $this->registerMapper->delete($this->registerMapper->find((int) $id)); return new JSONResponse([]); } From ef6c1ef956ba735bda06602fdb8b77a1c6388b48 Mon Sep 17 00:00:00 2001 From: Thijn Date: Thu, 26 Sep 2024 13:47:53 +0200 Subject: [PATCH 15/55] consistency --- lib/Db/Source.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Db/Source.php b/lib/Db/Source.php index 017285b..9203b6e 100644 --- a/lib/Db/Source.php +++ b/lib/Db/Source.php @@ -17,11 +17,11 @@ class Source extends Entity implements JsonSerializable public function __construct() { $this->addType(fieldName: 'title', type: 'string'); - $this->addType('description', 'string'); - $this->addType('databaseUrl', 'string'); - $this->addType('type', 'string'); - $this->addType('updated', 'datetime'); - $this->addType('created', 'datetime'); + $this->addType(fieldName: 'description', type: 'string'); + $this->addType(fieldName: 'databaseUrl', type: 'string'); + $this->addType(fieldName: 'type', type: 'string'); + $this->addType(fieldName: 'updated', type: 'datetime'); + $this->addType(fieldName: 'created', type: 'datetime'); } public function getJsonFields(): array From 2b3867aebb2fc095690d8b7cd518deabf2a79f40 Mon Sep 17 00:00:00 2001 From: Thijn Date: Thu, 26 Sep 2024 14:19:26 +0200 Subject: [PATCH 16/55] meer backend fixes --- lib/Migration/Version1Date20240924200009.php | 12 ++++++------ src/modals/register/EditRegister.vue | 2 -- src/modals/source/EditSource.vue | 2 -- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/Migration/Version1Date20240924200009.php b/lib/Migration/Version1Date20240924200009.php index 0d950fd..f13c802 100755 --- a/lib/Migration/Version1Date20240924200009.php +++ b/lib/Migration/Version1Date20240924200009.php @@ -45,8 +45,8 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt $table->addColumn('description', Types::TEXT, ['notnull' => false]); $table->addColumn('database_url', Types::STRING, ['notnull' => true, 'length' => 255]); $table->addColumn('type', Types::STRING, ['notnull' => true, 'length' => 64]); - $table->addColumn('updated', Types::DATETIME, ['notnull' => true]); - $table->addColumn('created', Types::DATETIME, ['notnull' => true]); + $table->addColumn('updated', Types::DATETIME, ['notnull' => true, 'default' => 'CURRENT_TIMESTAMP']); + $table->addColumn('created', Types::DATETIME, ['notnull' => true, 'default' => 'CURRENT_TIMESTAMP']); $table->setPrimaryKey(['id']); $table->addIndex(['title'], 'register_sources_title_index'); @@ -64,8 +64,8 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt $table->addColumn('properties', Types::JSON, ['notnull' => false]); $table->addColumn('archive', Types::JSON, ['notnull' => false]); $table->addColumn('source', Types::STRING, ['notnull' => true, 'length' => 64]); - $table->addColumn('updated', Types::DATETIME, ['notnull' => true]); - $table->addColumn('created', Types::DATETIME, ['notnull' => true]); + $table->addColumn('updated', Types::DATETIME, ['notnull' => true, 'default' => 'CURRENT_TIMESTAMP']); + $table->addColumn('created', Types::DATETIME, ['notnull' => true, 'default' => 'CURRENT_TIMESTAMP']); $table->setPrimaryKey(['id']); $table->addIndex(['title'], 'register_schemas_title_index'); @@ -80,8 +80,8 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt $table->addColumn('schemas', Types::JSON, ['notnull' => false]); $table->addColumn('source', Types::STRING, ['notnull' => true, 'length' => 64]); $table->addColumn('table_prefix', Types::STRING, ['notnull' => true, 'length' => 64]); - $table->addColumn('updated', Types::DATETIME, ['notnull' => true]); - $table->addColumn('created', Types::DATETIME, ['notnull' => true]); + $table->addColumn('updated', Types::DATETIME, ['notnull' => true, 'default' => 'CURRENT_TIMESTAMP']); + $table->addColumn('created', Types::DATETIME, ['notnull' => true, 'default' => 'CURRENT_TIMESTAMP']); $table->setPrimaryKey(['id']); $table->addIndex(['title'], 'registers_title_index'); diff --git a/src/modals/register/EditRegister.vue b/src/modals/register/EditRegister.vue index b7a642d..314b995 100644 --- a/src/modals/register/EditRegister.vue +++ b/src/modals/register/EditRegister.vue @@ -181,8 +181,6 @@ export default { registerStore.saveRegister({ ...this.registerItem, schemas: this.schemas?.value?.map((schema) => schema.id) || [], - created: !this.registerItem?.id ? new Date().toISOString() : this.registerItem.created, - updated: this.registerItem?.id ? new Date().toISOString() : null, }).then(({ response }) => { this.success = response.ok this.error = false diff --git a/src/modals/source/EditSource.vue b/src/modals/source/EditSource.vue index 48a5677..44f2e51 100644 --- a/src/modals/source/EditSource.vue +++ b/src/modals/source/EditSource.vue @@ -133,8 +133,6 @@ export default { sourceStore.saveSource({ ...this.sourceItem, - created: !this.sourceItem?.id ? new Date().toISOString() : this.sourceItem.created, - updated: this.sourceItem?.id ? new Date().toISOString() : null, }).then(({ response }) => { this.success = response.ok this.error = false From 82f866b6da7a7ed4ab3ce00498ae654ad8a5f7d5 Mon Sep 17 00:00:00 2001 From: Thijn Date: Thu, 26 Sep 2024 16:31:07 +0200 Subject: [PATCH 17/55] finished fixing the register modal and added source select --- lib/Db/Register.php | 2 +- src/entities/register/register.mock.ts | 46 ++++++---- src/entities/register/register.spec.ts | 109 ++++++++++++++---------- src/entities/register/register.ts | 84 +++++++++++------- src/entities/register/register.types.ts | 15 +++- src/entities/source/source.mock.ts | 27 ++++-- src/entities/source/source.ts | 64 +++++++++----- src/entities/source/source.types.ts | 21 +++-- src/modals/register/EditRegister.vue | 41 ++++++++- src/store/modules/register.js | 6 +- src/store/modules/source.js | 23 ++--- 11 files changed, 293 insertions(+), 145 deletions(-) diff --git a/lib/Db/Register.php b/lib/Db/Register.php index 68ad102..6cf8351 100644 --- a/lib/Db/Register.php +++ b/lib/Db/Register.php @@ -19,7 +19,7 @@ class Register extends Entity implements JsonSerializable public function __construct() { $this->addType(fieldName: 'title', type: 'string'); $this->addType(fieldName: 'description', type: 'string'); - $this->addType(fieldName: 'properties', type: 'json'); + $this->addType(fieldName: 'schemas', type: 'json'); $this->addType(fieldName: 'source', type: 'string'); $this->addType(fieldName: 'tablePrefix', type: 'string'); $this->addType(fieldName:'updated', type: 'datetime'); diff --git a/src/entities/register/register.mock.ts b/src/entities/register/register.mock.ts index 2221a7d..108b32f 100644 --- a/src/entities/register/register.mock.ts +++ b/src/entities/register/register.mock.ts @@ -2,22 +2,34 @@ import { Register } from './register' import { TRegister } from './register.types' export const mockRegisterData = (): TRegister[] => [ - { - id: "1234a1e5-b54d-43ad-abd1-4b5bff5fcd3f", - name: "Character Register", - description: "Stores character data for the game", - schemas: ["5678a1e5-b54d-43ad-abd1-4b5bff5fcd3f"], - databaseId: "db1-a1e5-b54d-43ad-abd1-4b5bff5fcd3f", - tablePrefix: "character_" - }, - { - id: "5678a1e5-b54d-43ad-abd1-4b5bff5fcd3f", - name: "Item Register", - description: "Stores item data for the game", - schemas: ["9012a1e5-b54d-43ad-abd1-4b5bff5fcd3f"], - databaseId: "db2-a1e5-b54d-43ad-abd1-4b5bff5fcd3f", - tablePrefix: "item_" - } + { + id: '1234a1e5-b54d-43ad-abd1-4b5bff5fcd3f', + title: 'Character Register', + description: 'Stores character data for the game', + schemas: ['5678a1e5-b54d-43ad-abd1-4b5bff5fcd3f'], + source: '1', + databaseId: 'db1-a1e5-b54d-43ad-abd1-4b5bff5fcd3f', + tablePrefix: 'character_', + created: { + date: new Date().toISOString(), + timezone_type: 3, + timezone: 'UTC', + }, + }, + { + id: '5678a1e5-b54d-43ad-abd1-4b5bff5fcd3f', + title: 'Item Register', + description: 'Stores item data for the game', + schemas: ['9012a1e5-b54d-43ad-abd1-4b5bff5fcd3f'], + source: '1', + databaseId: 'db2-a1e5-b54d-43ad-abd1-4b5bff5fcd3f', + tablePrefix: 'item_', + created: { + date: new Date().toISOString(), + timezone_type: 3, + timezone: 'UTC', + }, + }, ] -export const mockRegister = (data: TRegister[] = mockRegisterData()): TRegister[] => data.map(item => new Register(item)) \ No newline at end of file +export const mockRegister = (data: TRegister[] = mockRegisterData()): TRegister[] => data.map(item => new Register(item)) diff --git a/src/entities/register/register.spec.ts b/src/entities/register/register.spec.ts index 20b0124..41d0666 100644 --- a/src/entities/register/register.spec.ts +++ b/src/entities/register/register.spec.ts @@ -1,49 +1,68 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { Register } from './register' import { mockRegisterData } from './register.mock' describe('Register Entity', () => { - it('should create a Register entity with full data', () => { - const register = new Register(mockRegisterData()[0]) - - expect(register).toBeInstanceOf(Register) - expect(register).toEqual(mockRegisterData()[0]) - expect(register.validate().success).toBe(true) - }) - - it('should create a Register entity with partial data', () => { - const partialData = { - name: 'Partial Register', - description: 'A register with partial data', - schemas: [] as any[], // Explicitly typing schemas as any[] - databaseId: 'db1-a1e5-b54d-43ad-abd1-4b5bff5fcd3f' - } - const register = new Register(partialData) - - expect(register).toBeInstanceOf(Register) - expect(register.id).toBe('') - expect(register.name).toBe(partialData.name) - expect(register.tablePrefix).toBe('') - expect(register.validate().success).toBe(true) - }) - - it('should fail validation with invalid data', () => { - const invalidData = { - name: '', - description: 'Invalid register', - schemas: [] as any[], // Explicitly type the schemas property - databaseId: '' - } - const register = new Register(invalidData) - - expect(register).toBeInstanceOf(Register) - expect(register.validate().success).toBe(false) - }) - - it('should correctly combine database and register prefixes', () => { - const register = new Register(mockRegisterData()[0]) - - expect(register.getFullTablePrefix('myorg_')).toBe('myorg_character_') - expect(register.getFullTablePrefix('myorg_')).toBe('myorg_character_') - expect(register.getFullTablePrefix('')).toBe('character_') - }) -}) \ No newline at end of file + it('should create a Register entity with full data', () => { + const register = new Register(mockRegisterData()[0]) + + expect(register).toBeInstanceOf(Register) + expect(register).toEqual(mockRegisterData()[0]) + expect(register.validate().success).toBe(true) + }) + + it('should create a Register entity with partial data', () => { + const partialData = { + name: 'Partial Register', + description: 'A register with partial data', + schemas: [] as any[], // Explicitly typing schemas as any[] + databaseId: 'db1-a1e5-b54d-43ad-abd1-4b5bff5fcd3f', + title: 'Partial Register Title', + source: 'Test Source', + created: { + date: new Date().toISOString(), + timezone_type: 3, + timezone: 'UTC', + }, + } + const register = new Register(partialData) + + expect(register).toBeInstanceOf(Register) + expect(register.id).toBe('') + expect(register.title).toBe(partialData.title) + expect(register.tablePrefix).toBe('') + expect(register.validate().success).toBe(true) + }) + + it('should fail validation with invalid data', () => { + const invalidData = { + name: '', + description: 'Invalid register', + schemas: [] as any[], // Explicitly type the schemas property + databaseId: '', + title: '', + source: '', + created: { + date: new Date().toISOString(), + timezone_type: 3, + timezone: 'UTC', + }, + } + const register = new Register(invalidData) + + expect(register).toBeInstanceOf(Register) + expect(register.validate().success).toBe(false) + expect(register.validate().error?.issues).toContainEqual(expect.objectContaining({ + path: ['name'], + message: 'String must contain at least 1 character(s)', + })) + }) + + it('should correctly combine database and register prefixes', () => { + const register = new Register(mockRegisterData()[0]) + + expect(register.getFullTablePrefix('myorg_')).toBe('myorg_character_') + expect(register.getFullTablePrefix('myorg_')).toBe('myorg_character_') + expect(register.getFullTablePrefix('')).toBe('character_') + }) +}) diff --git a/src/entities/register/register.ts b/src/entities/register/register.ts index 5085c59..a5b112d 100644 --- a/src/entities/register/register.ts +++ b/src/entities/register/register.ts @@ -2,36 +2,62 @@ import { SafeParseReturnType, z } from 'zod' import { TRegister } from './register.types' export class Register implements TRegister { - public id: string - public name: string - public description: string - public schemas: string[] - public databaseId: string - public tablePrefix: string - - constructor(register: TRegister) { - this.id = register.id || '' - this.name = register.name - this.description = register.description - this.schemas = register.schemas || [] - this.databaseId = register.databaseId - this.tablePrefix = register.tablePrefix || '' - } - public validate(): SafeParseReturnType { - const schema = z.object({ - id: z.string().min(1), - name: z.string().min(1), - description: z.string(), - schemas: z.array(z.string()), - databaseId: z.string().min(1), - tablePrefix: z.string() - }) - - return schema.safeParse(this) + public id: string + public title: string + public description: string + public schemas: string[] + public source: string + public databaseId: string + public tablePrefix: string + public updated: { + date: string; + timezone_type: number; + timezone: string; } - public getFullTablePrefix(databasePrefix: string): string { - return `${databasePrefix}${this.tablePrefix}`.replace(/_{2,}/g, '_') + public created: { + date: string; + timezone_type: number; + timezone: string; } -} \ No newline at end of file + + constructor(register: TRegister) { + this.id = register.id || '' + this.title = register.title + this.description = register.description + this.schemas = register.schemas || [] + this.source = register.source || '' + this.databaseId = register.databaseId + this.tablePrefix = register.tablePrefix || '' + this.updated = register.updated || { + date: '', + timezone_type: 0, + timezone: '', + } + this.created = register.created || { + date: '', + timezone_type: 0, + timezone: '', + } + } + + public validate(): SafeParseReturnType { + const schema = z.object({ + id: z.string().min(1), + title: z.string().min(1), + description: z.string(), + schemas: z.array(z.string()), + source: z.string(), + databaseId: z.string().min(1), + tablePrefix: z.string(), + }) + + return schema.safeParse(this) + } + + public getFullTablePrefix(databasePrefix: string): string { + return `${databasePrefix}${this.tablePrefix}`.replace(/_{2,}/g, '_') + } + +} diff --git a/src/entities/register/register.types.ts b/src/entities/register/register.types.ts index 06566cd..526081a 100644 --- a/src/entities/register/register.types.ts +++ b/src/entities/register/register.types.ts @@ -1,8 +1,19 @@ export type TRegister = { id?: string - name: string + title: string description: string schemas: string[] // Array of Schema UUIDs + source: string // Reference to the Source entity databaseId: string // Reference to the Database entity tablePrefix?: string -} \ No newline at end of file + updated?: { + date: string; + timezone_type: number; + timezone: string; + } + created: { + date: string; + timezone_type: number; + timezone: string; + } +} diff --git a/src/entities/source/source.mock.ts b/src/entities/source/source.mock.ts index aa4be7d..82aaa42 100644 --- a/src/entities/source/source.mock.ts +++ b/src/entities/source/source.mock.ts @@ -2,13 +2,24 @@ import { Source } from './source' import { TSource } from './source.types' export const mockSourceData = (): TSource[] => [ - { - id: "5678a1e5-b54d-43ad-abd1-4b5bff5fcd3f", - name: "Main PostgreSQL Database", - description: "Primary database for user data", - databaseUrl: "postgresql://user:password@localhost:5432/maindb" - }, - // ... existing code ... + { + id: 1, + title: 'Main PostgreSQL Database', + description: 'Primary database for user data', + databaseUrl: 'postgresql://user:password@localhost:5432/maindb', + type: 'postgresql', + updated: { + date: '2024-03-15 09:30:00.000000', + timezone_type: 3, + timezone: 'UTC', + }, + created: { + date: '2024-03-15 09:30:00.000000', + timezone_type: 3, + timezone: 'UTC', + }, + }, + // ... existing code ... ] -export const mockSource = (data: TSource[] = mockSourceData()): TSource[] => data.map(item => new Source(item)) \ No newline at end of file +export const mockSource = (data: TSource[] = mockSourceData()): TSource[] => data.map(item => new Source(item)) diff --git a/src/entities/source/source.ts b/src/entities/source/source.ts index 5a1141b..397ca67 100644 --- a/src/entities/source/source.ts +++ b/src/entities/source/source.ts @@ -2,26 +2,52 @@ import { SafeParseReturnType, z } from 'zod' import { TSource } from './source.types' export class Source implements TSource { - public id: string - public name: string - public description: string - public databaseUrl: string - constructor(source: TSource) { - this.id = source.id || '' - this.name = source.name || '' - this.description = source.description || '' - this.databaseUrl = source.databaseUrl || '' + public id: string | number + public title: string + public description: string + public databaseUrl: string + public type: string + public updated: { + date: string; + timezone_type: number; + timezone: string; } - public validate(): SafeParseReturnType { - const schema = z.object({ - id: z.string().min(1), - name: z.string().min(1), - description: z.string(), - databaseUrl: z.string().url(), - }) - - return schema.safeParse(this) + public created: { + date: string; + timezone_type: number; + timezone: string; } -} \ No newline at end of file + + constructor(source: TSource) { + this.id = source.id || '' + this.title = source.title || '' + this.description = source.description || '' + this.databaseUrl = source.databaseUrl || '' + this.type = source.type || '' + this.updated = source.updated || { + date: '', + timezone_type: 0, + timezone: '', + } + this.created = source.created || { + date: '', + timezone_type: 0, + timezone: '', + } + } + + public validate(): SafeParseReturnType { + const schema = z.object({ + id: z.union([z.string(), z.number()]), + title: z.string().min(1), + description: z.string(), + databaseUrl: z.string().url(), + type: z.string(), + }) + + return schema.safeParse(this) + } + +} diff --git a/src/entities/source/source.types.ts b/src/entities/source/source.types.ts index 8636af4..bb45da5 100644 --- a/src/entities/source/source.types.ts +++ b/src/entities/source/source.types.ts @@ -1,6 +1,17 @@ export type TSource = { - id?: string - name: string - description: string - databaseUrl: string -} \ No newline at end of file + id?: string | number; + title: string; + description: string; + databaseUrl: string; + type: string; + updated: { + date: string; + timezone_type: number; + timezone: string; + }; + created: { + date: string; + timezone_type: number; + timezone: string; + }; +} diff --git a/src/modals/register/EditRegister.vue b/src/modals/register/EditRegister.vue index 314b995..676babc 100644 --- a/src/modals/register/EditRegister.vue +++ b/src/modals/register/EditRegister.vue @@ -1,5 +1,5 @@ diff --git a/src/views/source/SourceDetails.vue b/src/views/source/SourceDetails.vue index c788f13..3ea2748 100644 --- a/src/views/source/SourceDetails.vue +++ b/src/views/source/SourceDetails.vue @@ -1,5 +1,5 @@ diff --git a/src/views/source/SourcesList.vue b/src/views/source/SourcesList.vue index 6a1d0ad..f9acb2d 100644 --- a/src/views/source/SourcesList.vue +++ b/src/views/source/SourcesList.vue @@ -33,7 +33,7 @@ import { sourceStore, navigationStore, searchStore } from '../../store/store.js'
From 11eaf9f468f84ea4c1ba18a696aad09cbd41734a Mon Sep 17 00:00:00 2001 From: Thijn Date: Fri, 27 Sep 2024 13:49:51 +0200 Subject: [PATCH 19/55] applied fixes from REG-10 to working pages this is so I can pull these fixes to other issues without having to wait on REGISTER-10 to be merged --- lib/Db/Register.php | 2 +- lib/Db/Source.php | 10 +++++----- lib/Migration/Version1Date20240924200009.php | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/Db/Register.php b/lib/Db/Register.php index 68ad102..6cf8351 100644 --- a/lib/Db/Register.php +++ b/lib/Db/Register.php @@ -19,7 +19,7 @@ class Register extends Entity implements JsonSerializable public function __construct() { $this->addType(fieldName: 'title', type: 'string'); $this->addType(fieldName: 'description', type: 'string'); - $this->addType(fieldName: 'properties', type: 'json'); + $this->addType(fieldName: 'schemas', type: 'json'); $this->addType(fieldName: 'source', type: 'string'); $this->addType(fieldName: 'tablePrefix', type: 'string'); $this->addType(fieldName:'updated', type: 'datetime'); diff --git a/lib/Db/Source.php b/lib/Db/Source.php index 017285b..9203b6e 100644 --- a/lib/Db/Source.php +++ b/lib/Db/Source.php @@ -17,11 +17,11 @@ class Source extends Entity implements JsonSerializable public function __construct() { $this->addType(fieldName: 'title', type: 'string'); - $this->addType('description', 'string'); - $this->addType('databaseUrl', 'string'); - $this->addType('type', 'string'); - $this->addType('updated', 'datetime'); - $this->addType('created', 'datetime'); + $this->addType(fieldName: 'description', type: 'string'); + $this->addType(fieldName: 'databaseUrl', type: 'string'); + $this->addType(fieldName: 'type', type: 'string'); + $this->addType(fieldName: 'updated', type: 'datetime'); + $this->addType(fieldName: 'created', type: 'datetime'); } public function getJsonFields(): array diff --git a/lib/Migration/Version1Date20240924200009.php b/lib/Migration/Version1Date20240924200009.php index 0d950fd..f13c802 100755 --- a/lib/Migration/Version1Date20240924200009.php +++ b/lib/Migration/Version1Date20240924200009.php @@ -45,8 +45,8 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt $table->addColumn('description', Types::TEXT, ['notnull' => false]); $table->addColumn('database_url', Types::STRING, ['notnull' => true, 'length' => 255]); $table->addColumn('type', Types::STRING, ['notnull' => true, 'length' => 64]); - $table->addColumn('updated', Types::DATETIME, ['notnull' => true]); - $table->addColumn('created', Types::DATETIME, ['notnull' => true]); + $table->addColumn('updated', Types::DATETIME, ['notnull' => true, 'default' => 'CURRENT_TIMESTAMP']); + $table->addColumn('created', Types::DATETIME, ['notnull' => true, 'default' => 'CURRENT_TIMESTAMP']); $table->setPrimaryKey(['id']); $table->addIndex(['title'], 'register_sources_title_index'); @@ -64,8 +64,8 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt $table->addColumn('properties', Types::JSON, ['notnull' => false]); $table->addColumn('archive', Types::JSON, ['notnull' => false]); $table->addColumn('source', Types::STRING, ['notnull' => true, 'length' => 64]); - $table->addColumn('updated', Types::DATETIME, ['notnull' => true]); - $table->addColumn('created', Types::DATETIME, ['notnull' => true]); + $table->addColumn('updated', Types::DATETIME, ['notnull' => true, 'default' => 'CURRENT_TIMESTAMP']); + $table->addColumn('created', Types::DATETIME, ['notnull' => true, 'default' => 'CURRENT_TIMESTAMP']); $table->setPrimaryKey(['id']); $table->addIndex(['title'], 'register_schemas_title_index'); @@ -80,8 +80,8 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt $table->addColumn('schemas', Types::JSON, ['notnull' => false]); $table->addColumn('source', Types::STRING, ['notnull' => true, 'length' => 64]); $table->addColumn('table_prefix', Types::STRING, ['notnull' => true, 'length' => 64]); - $table->addColumn('updated', Types::DATETIME, ['notnull' => true]); - $table->addColumn('created', Types::DATETIME, ['notnull' => true]); + $table->addColumn('updated', Types::DATETIME, ['notnull' => true, 'default' => 'CURRENT_TIMESTAMP']); + $table->addColumn('created', Types::DATETIME, ['notnull' => true, 'default' => 'CURRENT_TIMESTAMP']); $table->setPrimaryKey(['id']); $table->addIndex(['title'], 'registers_title_index'); From b1a2dd4a66fdda99eaf542700cb5478be783985d Mon Sep 17 00:00:00 2001 From: Thijn Date: Fri, 27 Sep 2024 15:48:02 +0200 Subject: [PATCH 20/55] finished register schema tab --- .eslintrc.js | 1 + lib/Controller/SchemasController.php | 52 ++++++++--------- lib/Db/Schema.php | 5 +- src/entities/schema/schema.mock.ts | 36 ++++++------ src/entities/schema/schema.spec.ts | 18 +----- src/entities/schema/schema.ts | 36 +++++++++--- src/entities/schema/schema.types.ts | 12 +++- src/modals/schema/EditSchema.vue | 45 +++++++++++++-- src/store/modules/schema.js | 3 + src/store/modules/source.js | 3 + src/views/register/RegisterDetails.vue | 80 +++++++++++++++++++++++++- src/views/schema/SchemaDetails.vue | 6 +- src/views/schema/SchemasList.vue | 2 +- 13 files changed, 216 insertions(+), 83 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 9175db9..2a33e82 100755 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,5 +5,6 @@ module.exports = { rules: { 'jsdoc/require-jsdoc': 'off', 'vue/first-attribute-linebreak': 'off', + '@typescript-eslint/no-explicit-any': 'off', }, } diff --git a/lib/Controller/SchemasController.php b/lib/Controller/SchemasController.php index 7f7badf..82f4223 100644 --- a/lib/Controller/SchemasController.php +++ b/lib/Controller/SchemasController.php @@ -4,8 +4,8 @@ use OCA\OpenRegister\Service\ObjectService; use OCA\OpenRegister\Service\SearchService; -use OCA\OpenRegister\Db\Source; -use OCA\OpenRegister\Db\SourceMapper; +use OCA\OpenRegister\Db\Schema; +use OCA\OpenRegister\Db\SchemaMapper; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\JSONResponse; @@ -15,7 +15,7 @@ class SchemasController extends Controller { /** - * Constructor for the SourcesController + * Constructor for the SchemasController * * @param string $appName The name of the app * @param IRequest $request The request object @@ -25,7 +25,7 @@ public function __construct( $appName, IRequest $request, private readonly IAppConfig $config, - private readonly SourceMapper $sourceMapper + private readonly SchemaMapper $schemaMapper ) { parent::__construct($appName, $request); @@ -51,14 +51,14 @@ public function page(): TemplateResponse } /** - * Retrieves a list of all sources + * Retrieves a list of all schemas * - * This method returns a JSON response containing an array of all sources in the system. + * This method returns a JSON response containing an array of all schemas in the system. * * @NoAdminRequired * @NoCSRFRequired * - * @return JSONResponse A JSON response containing the list of sources + * @return JSONResponse A JSON response containing the list of schemas */ public function index(ObjectService $objectService, SearchService $searchService): JSONResponse { @@ -69,38 +69,38 @@ public function index(ObjectService $objectService, SearchService $searchService $searchConditions = $searchService->createMySQLSearchConditions(filters: $filters, fieldsToSearch: $fieldsToSearch); $filters = $searchService->unsetSpecialQueryParams(filters: $filters); - return new JSONResponse(['results' => $this->sourceMapper->findAll(limit: null, offset: null, filters: $filters, searchConditions: $searchConditions, searchParams: $searchParams)]); + return new JSONResponse(['results' => $this->schemaMapper->findAll(limit: null, offset: null, filters: $filters, searchConditions: $searchConditions, searchParams: $searchParams)]); } /** - * Retrieves a single source by its ID + * Retrieves a single schema by its ID * - * This method returns a JSON response containing the details of a specific source. + * This method returns a JSON response containing the details of a specific schema. * * @NoAdminRequired * @NoCSRFRequired * - * @param string $id The ID of the source to retrieve - * @return JSONResponse A JSON response containing the source details + * @param string $id The ID of the schema to retrieve + * @return JSONResponse A JSON response containing the schema details */ public function show(string $id): JSONResponse { try { - return new JSONResponse($this->sourceMapper->find(id: (int) $id)); + return new JSONResponse($this->schemaMapper->find(id: (int) $id)); } catch (DoesNotExistException $exception) { return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404); } } /** - * Creates a new source + * Creates a new schema * - * This method creates a new source based on POST data. + * This method creates a new schema based on POST data. * * @NoAdminRequired * @NoCSRFRequired * - * @return JSONResponse A JSON response containing the created source + * @return JSONResponse A JSON response containing the created schema */ public function create(): JSONResponse { @@ -116,19 +116,19 @@ public function create(): JSONResponse unset($data['id']); } - return new JSONResponse($this->sourceMapper->createFromArray(object: $data)); + return new JSONResponse($this->schemaMapper->createFromArray(object: $data)); } /** - * Updates an existing source + * Updates an existing schema * - * This method updates an existing source based on its ID. + * This method updates an existing schema based on its ID. * * @NoAdminRequired * @NoCSRFRequired * - * @param string $id The ID of the source to update - * @return JSONResponse A JSON response containing the updated source details + * @param string $id The ID of the schema to update + * @return JSONResponse A JSON response containing the updated schema details */ public function update(int $id): JSONResponse { @@ -142,23 +142,23 @@ public function update(int $id): JSONResponse if (isset($data['id'])) { unset($data['id']); } - return new JSONResponse($this->sourceMapper->updateFromArray(id: (int) $id, object: $data)); + return new JSONResponse($this->schemaMapper->updateFromArray(id: (int) $id, object: $data)); } /** - * Deletes a source + * Deletes a schema * - * This method deletes a source based on its ID. + * This method deletes a schema based on its ID. * * @NoAdminRequired * @NoCSRFRequired * - * @param string $id The ID of the source to delete + * @param string $id The ID of the schema to delete * @return JSONResponse An empty JSON response */ public function destroy(int $id): JSONResponse { - $this->sourceMapper->delete($this->sourceMapper->find((int) $id)); + $this->schemaMapper->delete($this->schemaMapper->find((int) $id)); return new JSONResponse([]); } diff --git a/lib/Db/Schema.php b/lib/Db/Schema.php index 351d94b..35b8f78 100644 --- a/lib/Db/Schema.php +++ b/lib/Db/Schema.php @@ -8,6 +8,7 @@ class Schema extends Entity implements JsonSerializable { + protected ?string $title = null; protected ?string $version = null; protected ?string $description = null; protected ?string $summary = null; @@ -102,8 +103,8 @@ public function jsonSerialize(): array 'properties' => $properties, 'archive' => $this->archive, 'source' => $this->source, - 'updated' => $this->updated, - 'created' => $this->created + 'updated' => isset($this->updated) ? $this->updated->format('c') : null, + 'created' => isset($this->created) ? $this->created->format('c') : null, ]; $jsonFields = $this->getJsonFields(); diff --git a/src/entities/schema/schema.mock.ts b/src/entities/schema/schema.mock.ts index 59a698f..a0c6aab 100644 --- a/src/entities/schema/schema.mock.ts +++ b/src/entities/schema/schema.mock.ts @@ -4,31 +4,35 @@ import { TSchema } from './schema.types' export const mockSchemaData = (): TSchema[] => [ { id: '5678a1e5-b54d-43ad-abd1-4b5bff5fcd3f', - name: 'Character Schema', + title: 'Character Schema', description: 'Defines the structure for character data', - jsonSchema: { - type: 'object', - properties: { - name: { type: 'string' }, - description: { type: 'string' }, - }, - required: ['name'], + summary: 'Character Schema', + required: ['name'], + properties: { + name: { type: 'string' }, + description: { type: 'string' }, }, version: '1.0.0', + source: 'https://example.com/schemas/character.json', + archive: [], + updated: new Date().toISOString(), + created: new Date().toISOString(), }, { id: '9012a1e5-b54d-43ad-abd1-4b5bff5fcd3f', - name: 'Item Schema', + title: 'Item Schema', description: 'Defines the structure for item data', - jsonSchema: { - type: 'object', - properties: { - name: { type: 'string' }, - value: { type: 'number' }, - }, - required: ['name', 'value'], + summary: 'Item Schema', + required: ['name', 'value'], + properties: { + name: { type: 'string' }, + value: { type: 'number' }, }, version: '1.1.0', + source: 'https://example.com/schemas/item.json', + archive: [], + updated: new Date().toISOString(), + created: new Date().toISOString(), }, ] diff --git a/src/entities/schema/schema.spec.ts b/src/entities/schema/schema.spec.ts index a5b2eae..7081ba9 100644 --- a/src/entities/schema/schema.spec.ts +++ b/src/entities/schema/schema.spec.ts @@ -11,28 +11,16 @@ describe('Schema Entity', () => { }) it('should create a Schema entity with partial data', () => { - const partialData = { - name: 'Partial Schema', - description: 'A schema with partial data', - jsonSchema: {}, - version: '0.1.0', - } - const schema = new Schema(partialData) + const schema = new Schema(mockSchemaData()[0]) expect(schema).toBeInstanceOf(Schema) expect(schema.id).toBe('') - expect(schema.name).toBe(partialData.name) + expect(schema.title).toBe(mockSchemaData()[0].title) expect(schema.validate().success).toBe(true) }) it('should fail validation with invalid data', () => { - const invalidData = { - name: '', - description: 'Invalid schema', - jsonSchema: {}, - version: '1.0.0', - } - const schema = new Schema(invalidData) + const schema = new Schema(mockSchemaData()[1]) expect(schema).toBeInstanceOf(Schema) expect(schema.validate().success).toBe(false) diff --git a/src/entities/schema/schema.ts b/src/entities/schema/schema.ts index f29b993..ca34dcf 100644 --- a/src/entities/schema/schema.ts +++ b/src/entities/schema/schema.ts @@ -4,26 +4,44 @@ import { TSchema } from './schema.types' export class Schema implements TSchema { public id: string - public name: string - public description: string - public jsonSchema: object + public title: string public version: string + public description: string + public summary: string + public required: string[] + public properties: object + public archive: Record + public source: string + public updated: string + public created: string constructor(schema: TSchema) { this.id = schema.id || '' - this.name = schema.name || '' + this.title = schema.title || '' + this.version = schema.version || '' this.description = schema.description || '' - this.jsonSchema = schema.jsonSchema || {} - this.version = schema.version || '1.0.0' + this.summary = schema.summary || '' + this.required = schema.required || [] + this.properties = schema.properties || {} + this.archive = schema.archive || {} + this.source = schema.source || '' + this.updated = schema.updated || '' + this.created = schema.created || '' } public validate(): SafeParseReturnType { const schema = z.object({ id: z.string().min(1), - name: z.string().min(1), - description: z.string(), - jsonSchema: z.object({}), + title: z.string().min(1), version: z.string(), + description: z.string(), + summary: z.string(), + required: z.array(z.string()), + properties: z.object({}), + archive: z.object({}), + source: z.string(), + updated: z.string(), + created: z.string(), }) return schema.safeParse(this) diff --git a/src/entities/schema/schema.types.ts b/src/entities/schema/schema.types.ts index b55db9a..e333a29 100644 --- a/src/entities/schema/schema.types.ts +++ b/src/entities/schema/schema.types.ts @@ -1,7 +1,13 @@ export type TSchema = { id?: string - name: string - description: string - jsonSchema: object + title: string version: string + description: string + summary: string + required: string[] + properties: object + archive: object + source: string + updated: string; + created: string; } diff --git a/src/modals/schema/EditSchema.vue b/src/modals/schema/EditSchema.vue index 1d9c7de..ef79977 100644 --- a/src/modals/schema/EditSchema.vue +++ b/src/modals/schema/EditSchema.vue @@ -1,5 +1,5 @@ @@ -20,7 +21,7 @@ import Dashboard from './dashboard/DashboardIndex.vue' import RegistersIndex from './register/RegistersIndex.vue' import SourcesIndex from './source/SourcesIndex.vue' import SchemasIndex from './schema/SchemasIndex.vue' - +import ObjectsIndex from './object/ObjectsIndex.vue' export default { name: 'Views', components: { @@ -29,6 +30,7 @@ export default { RegistersIndex, SourcesIndex, SchemasIndex, + ObjectsIndex, }, } From bd298a267ecfc407aff48f99ac49b8362311b924 Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Mon, 30 Sep 2024 16:57:09 +0200 Subject: [PATCH 30/55] Fix for missing uuid --- lib/Db/ObjectEntityMapper.php | 7 +++++++ lib/Service/ObjectService.php | 1 + 2 files changed, 8 insertions(+) diff --git a/lib/Db/ObjectEntityMapper.php b/lib/Db/ObjectEntityMapper.php index a7e77a7..747ca40 100644 --- a/lib/Db/ObjectEntityMapper.php +++ b/lib/Db/ObjectEntityMapper.php @@ -7,6 +7,7 @@ use OCP\AppFramework\Db\QBMapper; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; +use Symfony\Component\Uid\Uuid; class ObjectEntityMapper extends QBMapper { @@ -119,6 +120,9 @@ public function createFromArray(array $object): Object { $obj = new Object(); $obj->hydrate(object: $object); + if($obj->getUuid() === null){ + $obj->setUuid(Uuid::v4()); + } return $this->insert(entity: $obj); } @@ -126,6 +130,9 @@ public function updateFromArray(int $id, array $object): Object { $obj = $this->find($id); $obj->hydrate($object); + if($obj->getUuid() === null){ + $obj->setUuid(Uuid::v4()); + } return $this->update($obj); } diff --git a/lib/Service/ObjectService.php b/lib/Service/ObjectService.php index e8ac3c3..00fd10f 100755 --- a/lib/Service/ObjectService.php +++ b/lib/Service/ObjectService.php @@ -10,6 +10,7 @@ use OCA\OpenRegister\Db\RegisterMapper; use OCA\OpenRegister\Db\ObjectEntity; use OCA\OpenRegister\Db\ObjectEntityMapper; +use Symfony\Component\Uid\Uuid; class ObjectService { From af0b9b334e86053c6bb3c078011cbfc828a5a609 Mon Sep 17 00:00:00 2001 From: Thijn Date: Mon, 30 Sep 2024 17:08:12 +0200 Subject: [PATCH 31/55] added modal with json verification --- lib/Db/ObjectEntityMapper.php | 22 +-- src/modals/Modals.vue | 6 + src/modals/object/DeleteObject.vue | 97 +++++++++++ src/modals/object/EditObject.vue | 262 +++++++++++++++++++++++++++++ src/navigation/MainMenu.vue | 5 +- src/store/modules/register.js | 22 +-- src/store/modules/schema.js | 22 +-- 7 files changed, 393 insertions(+), 43 deletions(-) create mode 100644 src/modals/object/DeleteObject.vue create mode 100644 src/modals/object/EditObject.vue diff --git a/lib/Db/ObjectEntityMapper.php b/lib/Db/ObjectEntityMapper.php index 747ca40..b09d882 100644 --- a/lib/Db/ObjectEntityMapper.php +++ b/lib/Db/ObjectEntityMapper.php @@ -20,9 +20,9 @@ public function __construct(IDBConnection $db) * Find an object by ID * * @param int $id The ID of the object to find - * @return Object The object + * @return ObjectEntity The ObjectEntity */ - public function find(int $id): Object + public function find(int $id): ObjectEntity { $qb = $this->db->getQueryBuilder(); @@ -39,9 +39,9 @@ public function find(int $id): Object * Find an object by UUID * * @param string $uuid The UUID of the object to find - * @return Object The object + * @return ObjectEntity The object */ - public function findByUuid(string $uuid): Object + public function findByUuid(string $uuid): ObjectEntity { $qb = $this->db->getQueryBuilder(); @@ -59,9 +59,9 @@ public function findByUuid(string $uuid): Object * * @param string $register The register to find objects for * @param string $schema The schema to find objects for - * @return array An array of objects + * @return array An array of ObjectEntitys */ - public function findByRegisterAndSchema(string $register, string $schema): Object + public function findByRegisterAndSchema(string $register, string $schema): ObjectEntity { $qb = $this->db->getQueryBuilder(); @@ -78,14 +78,14 @@ public function findByRegisterAndSchema(string $register, string $schema): Objec } /** - * Find all objects + * Find all ObjectEntitys * * @param int $limit The number of objects to return * @param int $offset The offset of the objects to return * @param array $filters The filters to apply to the objects * @param array $searchConditions The search conditions to apply to the objects * @param array $searchParams The search parameters to apply to the objects - * @return array An array of objects + * @return array An array of ObjectEntitys */ public function findAll(?int $limit = null, ?int $offset = null, ?array $filters = [], ?array $searchConditions = [], ?array $searchParams = []): array { @@ -116,9 +116,9 @@ public function findAll(?int $limit = null, ?int $offset = null, ?array $filters return $this->findEntities(query: $qb); } - public function createFromArray(array $object): Object + public function createFromArray(array $object): ObjectEntity { - $obj = new Object(); + $obj = new ObjectEntity(); $obj->hydrate(object: $object); if($obj->getUuid() === null){ $obj->setUuid(Uuid::v4()); @@ -126,7 +126,7 @@ public function createFromArray(array $object): Object return $this->insert(entity: $obj); } - public function updateFromArray(int $id, array $object): Object + public function updateFromArray(int $id, array $object): ObjectEntity { $obj = $this->find($id); $obj->hydrate($object); diff --git a/src/modals/Modals.vue b/src/modals/Modals.vue index 9d770f8..3c2e196 100755 --- a/src/modals/Modals.vue +++ b/src/modals/Modals.vue @@ -7,6 +7,8 @@ + +
@@ -17,6 +19,8 @@ import EditSchema from './schema/EditSchema.vue' import DeleteSchema from './schema/DeleteSchema.vue' import EditSource from './source/EditSource.vue' import DeleteSource from './source/DeleteSource.vue' +import EditObject from './object/EditObject.vue' +import DeleteObject from './object/DeleteObject.vue' export default { name: 'Modals', @@ -27,6 +31,8 @@ export default { DeleteSchema, EditSource, DeleteSource, + EditObject, + DeleteObject, }, } diff --git a/src/modals/object/DeleteObject.vue b/src/modals/object/DeleteObject.vue new file mode 100644 index 0000000..638316d --- /dev/null +++ b/src/modals/object/DeleteObject.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/src/modals/object/EditObject.vue b/src/modals/object/EditObject.vue new file mode 100644 index 0000000..1f0bd68 --- /dev/null +++ b/src/modals/object/EditObject.vue @@ -0,0 +1,262 @@ + + + + + diff --git a/src/navigation/MainMenu.vue b/src/navigation/MainMenu.vue index dc08bd7..714b48e 100755 --- a/src/navigation/MainMenu.vue +++ b/src/navigation/MainMenu.vue @@ -20,9 +20,9 @@ import { navigationStore } from '../store/store.js' - + @@ -50,6 +50,7 @@ import Finance from 'vue-material-design-icons/Finance.vue' import DatabaseOutline from 'vue-material-design-icons/DatabaseOutline.vue' import FileTreeOutline from 'vue-material-design-icons/FileTreeOutline.vue' import DatabaseArrowRightOutline from 'vue-material-design-icons/DatabaseArrowRightOutline.vue' +import CubeOutline from 'vue-material-design-icons/CubeOutline.vue' export default { name: 'MainMenu', diff --git a/src/store/modules/register.js b/src/store/modules/register.js index 0f930bf..841dd72 100644 --- a/src/store/modules/register.js +++ b/src/store/modules/register.js @@ -25,23 +25,15 @@ export const useRegisterStore = defineStore('register', { if (search !== null && search !== '') { endpoint = endpoint + '?_search=' + search } - return fetch(endpoint, { + const response = await fetch(endpoint, { method: 'GET', }) - .then( - (response) => { - response.json().then( - (data) => { - this.setRegisterList(data.results) - }, - ) - }, - ) - .catch( - (err) => { - console.error(err) - }, - ) + + const data = (await response.json()).results + + this.setRegisterList(data) + + return { response, data } }, // New function to get a single register async getRegister(id) { diff --git a/src/store/modules/schema.js b/src/store/modules/schema.js index 7319b01..6db04b0 100644 --- a/src/store/modules/schema.js +++ b/src/store/modules/schema.js @@ -25,23 +25,15 @@ export const useSchemaStore = defineStore('schema', { if (search !== null && search !== '') { endpoint = endpoint + '?_search=' + search } - return fetch(endpoint, { + const response = await fetch(endpoint, { method: 'GET', }) - .then( - (response) => { - response.json().then( - (data) => { - this.setSchemaList(data.results) - }, - ) - }, - ) - .catch( - (err) => { - console.error(err) - }, - ) + + const data = (await response.json()).results + + this.setSchemaList(data) + + return { response, data } }, // Function to get a single schema async getSchema(id) { From e36a2d596a981cc16ff42c4f3c01f6dc84d1b1ba Mon Sep 17 00:00:00 2001 From: Thijn Date: Tue, 1 Oct 2024 11:22:28 +0200 Subject: [PATCH 32/55] fixed small issue causing 500 --- src/modals/object/EditObject.vue | 4 ++-- src/views/object/ObjectDetails.vue | 13 ++++--------- src/views/object/ObjectsList.vue | 4 ++-- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/modals/object/EditObject.vue b/src/modals/object/EditObject.vue index 1f0bd68..5ac07f1 100644 --- a/src/modals/object/EditObject.vue +++ b/src/modals/object/EditObject.vue @@ -90,7 +90,7 @@ import { objectStore, schemaStore, registerStore, navigationStore } from '../../ placeholder="{ "key": "value" }" :value.sync="objectItem.object" :error="!verifyJsonValidity(objectItem.object)" - :helper-text="!verifyJsonValidity(objectItem.object) && 'This is not valid JSON (optional)'" /> + :helper-text="!verifyJsonValidity(objectItem.object) ? 'This is not valid JSON (optional)' : ''" /> @@ -235,7 +235,7 @@ export default { objectStore.saveObject({ ...this.objectItem, - schemas: this.schemas?.value?.id || '', + schema: this.schemas?.value?.id || '', register: this.registers?.value?.id || '', }).then(({ response }) => { this.success = response.ok diff --git a/src/views/object/ObjectDetails.vue b/src/views/object/ObjectDetails.vue index 2a1fe8a..9fc3584 100644 --- a/src/views/object/ObjectDetails.vue +++ b/src/views/object/ObjectDetails.vue @@ -8,7 +8,7 @@ import { objectStore, navigationStore } from '../../store/store.js'

- {{ objectStore.objectItem.title }} + {{ objectStore.objectItem.uuid }}

@@ -29,15 +29,10 @@ import { objectStore, navigationStore } from '../../store/store.js'
- {{ objectStore.objectItem.description }} -
-
- Table Prefix: -

{{ objectStore.objectItem.tablePrefix }}

-
-
- +

+ {{ JSON.stringify(objectStore.objectItem.object, null, 2) }} +

diff --git a/src/views/object/ObjectsList.vue b/src/views/object/ObjectsList.vue index 68a8f37..4dae428 100644 --- a/src/views/object/ObjectsList.vue +++ b/src/views/object/ObjectsList.vue @@ -33,7 +33,7 @@ import { objectStore, navigationStore, searchStore } from '../../store/store.js'
@@ -43,7 +43,7 @@ import { objectStore, navigationStore, searchStore } from '../../store/store.js' :size="44" /> @@ -87,7 +87,7 @@ export default { response.ok && setTimeout(this.closeDialog, 2000) }).catch((error) => { this.success = false - this.error = error.message || 'Er is een fout opgetreden bij het verwijderen van het object' + this.error = error.message || 'An error occurred while deleting the object' }).finally(() => { this.loading = false }) diff --git a/src/modals/object/EditObject.vue b/src/modals/object/EditObject.vue index 5ac07f1..3255f4c 100644 --- a/src/modals/object/EditObject.vue +++ b/src/modals/object/EditObject.vue @@ -8,7 +8,7 @@ import { objectStore, schemaStore, registerStore, navigationStore } from '../../ size="normal" :can-close="false"> -

Object succesvol aangepast

+

Object successfully modified

{{ error }}

@@ -160,7 +160,7 @@ export default { ...objectStore.objectItem, schemas: objectStore.objectItem.schemas || '', register: objectStore.objectItem.register || '', - object: objectStore.objectItem.object || '', + object: JSON.stringify(objectStore.objectItem.object) || '', } } }, From b378331a95cd9ae97883bd24f9c1ba1b13ec3bdb Mon Sep 17 00:00:00 2001 From: Thijn Date: Tue, 1 Oct 2024 16:24:58 +0200 Subject: [PATCH 36/55] finished adding properties modal to schema --- package-lock.json | 40 +- package.json | 1 + src/entities/schema/schema.ts | 2 +- src/entities/schema/schema.types.ts | 4 +- src/modals/Modals.vue | 6 + src/modals/schema/DeleteSchemaProperty.vue | 122 +++++ src/modals/schema/EditSchemaProperty.vue | 495 +++++++++++++++++++++ src/store/modules/schema.js | 51 +-- src/views/schema/SchemaDetails.vue | 54 ++- src/views/schema/SchemasList.vue | 7 + 10 files changed, 743 insertions(+), 39 deletions(-) create mode 100644 src/modals/schema/DeleteSchemaProperty.vue create mode 100644 src/modals/schema/EditSchemaProperty.vue diff --git a/package-lock.json b/package-lock.json index c082b2f..84deeda 100755 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "remark-preset-lint-consistent": "^6.0.0", "remark-preset-lint-recommended": "^7.0.0", "style-loader": "^3.3.3", + "uuid": "^10.0.0", "vue": "^2.7.14", "vue-apexcharts": "^1.6.2", "vue-loader": "^15.11.1 <16.0.0", @@ -18876,6 +18877,16 @@ "websocket-driver": "^0.7.4" } }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "peer": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/source-map": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", @@ -21061,11 +21072,13 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "peer": true, + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } @@ -36000,6 +36013,15 @@ "faye-websocket": "^0.11.3", "uuid": "^8.3.2", "websocket-driver": "^0.7.4" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "peer": true + } } }, "source-map": { @@ -37601,11 +37623,9 @@ "peer": true }, "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "peer": true + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==" }, "v8-to-istanbul": { "version": "9.3.0", diff --git a/package.json b/package.json index 38887bd..29e5c3a 100755 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "remark-preset-lint-consistent": "^6.0.0", "remark-preset-lint-recommended": "^7.0.0", "style-loader": "^3.3.3", + "uuid": "^10.0.0", "vue": "^2.7.14", "vue-apexcharts": "^1.6.2", "vue-loader": "^15.11.1 <16.0.0", diff --git a/src/entities/schema/schema.ts b/src/entities/schema/schema.ts index ca34dcf..04d5654 100644 --- a/src/entities/schema/schema.ts +++ b/src/entities/schema/schema.ts @@ -9,7 +9,7 @@ export class Schema implements TSchema { public description: string public summary: string public required: string[] - public properties: object + public properties: Record public archive: Record public source: string public updated: string diff --git a/src/entities/schema/schema.types.ts b/src/entities/schema/schema.types.ts index e333a29..4d3dbdf 100644 --- a/src/entities/schema/schema.types.ts +++ b/src/entities/schema/schema.types.ts @@ -5,8 +5,8 @@ export type TSchema = { description: string summary: string required: string[] - properties: object - archive: object + properties: Record + archive: Record source: string updated: string; created: string; diff --git a/src/modals/Modals.vue b/src/modals/Modals.vue index 3c2e196..5841d55 100755 --- a/src/modals/Modals.vue +++ b/src/modals/Modals.vue @@ -5,6 +5,8 @@ + + @@ -17,6 +19,8 @@ import EditRegister from './register/EditRegister.vue' import DeleteRegister from './register/DeleteRegister.vue' import EditSchema from './schema/EditSchema.vue' import DeleteSchema from './schema/DeleteSchema.vue' +import EditSchemaProperty from './schema/EditSchemaProperty.vue' +import DeleteSchemaProperty from './schema/DeleteSchemaProperty.vue' import EditSource from './source/EditSource.vue' import DeleteSource from './source/DeleteSource.vue' import EditObject from './object/EditObject.vue' @@ -29,6 +33,8 @@ export default { DeleteRegister, EditSchema, DeleteSchema, + EditSchemaProperty, + DeleteSchemaProperty, EditSource, DeleteSource, EditObject, diff --git a/src/modals/schema/DeleteSchemaProperty.vue b/src/modals/schema/DeleteSchemaProperty.vue new file mode 100644 index 0000000..4bcaa47 --- /dev/null +++ b/src/modals/schema/DeleteSchemaProperty.vue @@ -0,0 +1,122 @@ + + + + + + + diff --git a/src/modals/schema/EditSchemaProperty.vue b/src/modals/schema/EditSchemaProperty.vue new file mode 100644 index 0000000..a528484 --- /dev/null +++ b/src/modals/schema/EditSchemaProperty.vue @@ -0,0 +1,495 @@ + + + + + + diff --git a/src/store/modules/schema.js b/src/store/modules/schema.js index 6db04b0..bef57f9 100644 --- a/src/store/modules/schema.js +++ b/src/store/modules/schema.js @@ -5,6 +5,7 @@ import { Schema } from '../../entities/index.js' export const useSchemaStore = defineStore('schema', { state: () => ({ schemaItem: false, + schemaPropertyKey: null, // holds a UUID of the property to edit schemaList: [], }), actions: { @@ -99,38 +100,38 @@ export const useSchemaStore = defineStore('schema', { schemaItem.updated = new Date().toISOString() - try { - const response = await fetch( - endpoint, - { - method, - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(schemaItem), + const response = await fetch( + endpoint, + { + method, + headers: { + 'Content-Type': 'application/json', }, - ) + body: JSON.stringify(schemaItem), + }, + ) - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`) - } + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } - const responseData = await response.json() + const responseData = await response.json() - if (!responseData || typeof responseData !== 'object') { - throw new Error('Invalid response data') - } + if (!responseData || typeof responseData !== 'object') { + throw new Error('Invalid response data') + } - const data = new Schema(responseData) + const data = new Schema(responseData) - this.setSchemaItem(data) - this.refreshSchemaList() + this.setSchemaItem(data) + this.refreshSchemaList() - return { response, data } - } catch (error) { - console.error('Error saving schema:', error) - throw new Error(`Failed to save schema: ${error.message}`) - } + return { response, data } + + }, + // schema properties + setSchemaPropertyKey(schemaPropertyKey) { + this.schemaPropertyKey = schemaPropertyKey }, }, }) diff --git a/src/views/schema/SchemaDetails.vue b/src/views/schema/SchemaDetails.vue index 4ae1846..fa262f3 100644 --- a/src/views/schema/SchemaDetails.vue +++ b/src/views/schema/SchemaDetails.vue @@ -21,6 +21,12 @@ import { schemaStore, navigationStore } from '../../store/store.js' Edit + + + Add Property + diff --git a/src/views/schema/SchemasList.vue b/src/views/schema/SchemasList.vue index 806487e..84e1660 100644 --- a/src/views/schema/SchemasList.vue +++ b/src/views/schema/SchemasList.vue @@ -52,6 +52,12 @@ import { schemaStore, navigationStore, searchStore } from '../../store/store.js' Edit + + + Add Property +
-
+
No properties found
- +
-
+
No logs found -
+
@@ -130,8 +130,6 @@ export default { DotsHorizontal, Pencil, TrashCanOutline, - BTabs, - BTab, }, } diff --git a/src/views/source/SourceDetails.vue b/src/views/source/SourceDetails.vue index c09702c..8b485bd 100644 --- a/src/views/source/SourceDetails.vue +++ b/src/views/source/SourceDetails.vue @@ -73,12 +73,12 @@ import { sourceStore, navigationStore, registerStore } from '../../store/store.j -
+
Geen registers gevonden
-
+
-
+
No logs found
From 6d2fcfb1fcbdc611f76a3786feba5f01ac2ab415 Mon Sep 17 00:00:00 2001 From: Wilco Louwerse Date: Fri, 4 Oct 2024 16:00:26 +0200 Subject: [PATCH 51/55] Some code cleanup --- lib/Db/ObjectEntity.php | 6 +++--- lib/Db/ObjectEntityMapper.php | 14 +++++++------- lib/Db/Register.php | 6 +++--- lib/Db/RegisterMapper.php | 2 +- lib/Db/Schema.php | 6 +++--- lib/Db/SchemaMapper.php | 2 +- lib/Db/Source.php | 6 +++--- lib/Db/SourceMapper.php | 2 +- lib/Service/SearchService.php | 30 +++++++++++++++--------------- 9 files changed, 37 insertions(+), 37 deletions(-) diff --git a/lib/Db/ObjectEntity.php b/lib/Db/ObjectEntity.php index 2035c41..7ecfe9d 100644 --- a/lib/Db/ObjectEntity.php +++ b/lib/Db/ObjectEntity.php @@ -37,11 +37,11 @@ public function hydrate(array $object): self { $jsonFields = $this->getJsonFields(); - if(isset($object['metadata']) === false) { + if (isset($object['metadata']) === false) { $object['metadata'] = []; } - foreach($object as $key => $value) { + foreach ($object as $key => $value) { if (in_array($key, $jsonFields) === true && $value === []) { $value = null; } @@ -70,4 +70,4 @@ public function jsonSerialize(): array 'created' => isset($this->created) ? $this->created->format('c') : null ]; } -} \ No newline at end of file +} diff --git a/lib/Db/ObjectEntityMapper.php b/lib/Db/ObjectEntityMapper.php index b09d882..55c0500 100644 --- a/lib/Db/ObjectEntityMapper.php +++ b/lib/Db/ObjectEntityMapper.php @@ -18,7 +18,7 @@ public function __construct(IDBConnection $db) /** * Find an object by ID - * + * * @param int $id The ID of the object to find * @return ObjectEntity The ObjectEntity */ @@ -37,7 +37,7 @@ public function find(int $id): ObjectEntity /** * Find an object by UUID - * + * * @param string $uuid The UUID of the object to find * @return ObjectEntity The object */ @@ -56,7 +56,7 @@ public function findByUuid(string $uuid): ObjectEntity /** * Find objects by register and schema - * + * * @param string $register The register to find objects for * @param string $schema The schema to find objects for * @return array An array of ObjectEntitys @@ -79,7 +79,7 @@ public function findByRegisterAndSchema(string $register, string $schema): Objec /** * Find all ObjectEntitys - * + * * @param int $limit The number of objects to return * @param int $offset The offset of the objects to return * @param array $filters The filters to apply to the objects @@ -96,7 +96,7 @@ public function findAll(?int $limit = null, ?int $offset = null, ?array $filters ->setMaxResults($limit) ->setFirstResult($offset); - foreach($filters as $filter => $value) { + foreach ($filters as $filter => $value) { if ($value === 'IS NOT NULL') { $qb->andWhere($qb->expr()->isNotNull($filter)); } elseif ($value === 'IS NULL') { @@ -120,7 +120,7 @@ public function createFromArray(array $object): ObjectEntity { $obj = new ObjectEntity(); $obj->hydrate(object: $object); - if($obj->getUuid() === null){ + if ($obj->getUuid() === null){ $obj->setUuid(Uuid::v4()); } return $this->insert(entity: $obj); @@ -130,7 +130,7 @@ public function updateFromArray(int $id, array $object): ObjectEntity { $obj = $this->find($id); $obj->hydrate($object); - if($obj->getUuid() === null){ + if ($obj->getUuid() === null){ $obj->setUuid(Uuid::v4()); } diff --git a/lib/Db/Register.php b/lib/Db/Register.php index 4d289fc..2bbd0cb 100644 --- a/lib/Db/Register.php +++ b/lib/Db/Register.php @@ -39,11 +39,11 @@ public function hydrate(array $object): self { $jsonFields = $this->getJsonFields(); - if(isset($object['metadata']) === false) { + if (isset($object['metadata']) === false) { $object['metadata'] = []; } - foreach($object as $key => $value) { + foreach ($object as $key => $value) { if (in_array($key, $jsonFields) === true && $value === []) { $value = null; } @@ -73,4 +73,4 @@ public function jsonSerialize(): array 'created' => isset($this->created) ? $this->created->format('c') : null ]; } -} \ No newline at end of file +} diff --git a/lib/Db/RegisterMapper.php b/lib/Db/RegisterMapper.php index 2e16cb2..3ec4b57 100644 --- a/lib/Db/RegisterMapper.php +++ b/lib/Db/RegisterMapper.php @@ -37,7 +37,7 @@ public function findAll(?int $limit = null, ?int $offset = null, ?array $filters ->setMaxResults($limit) ->setFirstResult($offset); - foreach($filters as $filter => $value) { + foreach ($filters as $filter => $value) { if ($value === 'IS NOT NULL') { $qb->andWhere($qb->expr()->isNotNull($filter)); } elseif ($value === 'IS NULL') { diff --git a/lib/Db/Schema.php b/lib/Db/Schema.php index 35b8f78..43a3157 100644 --- a/lib/Db/Schema.php +++ b/lib/Db/Schema.php @@ -45,11 +45,11 @@ public function hydrate(array $object): self { $jsonFields = $this->getJsonFields(); - if(isset($object['metadata']) === false) { + if (isset($object['metadata']) === false) { $object['metadata'] = []; } - foreach($object as $key => $value) { + foreach ($object as $key => $value) { if (in_array($key, $jsonFields) === true && $value === []) { $value = null; } @@ -77,7 +77,7 @@ public function jsonSerialize(): array } switch ($property['format']) { case 'string': - // For now array as string + // For now array as string case 'array': $properties[$key]['default'] = (string) $property; break; diff --git a/lib/Db/SchemaMapper.php b/lib/Db/SchemaMapper.php index 5750eea..a9f6716 100644 --- a/lib/Db/SchemaMapper.php +++ b/lib/Db/SchemaMapper.php @@ -37,7 +37,7 @@ public function findAll(?int $limit = null, ?int $offset = null, ?array $filters ->setMaxResults($limit) ->setFirstResult($offset); - foreach($filters as $filter => $value) { + foreach ($filters as $filter => $value) { if ($value === 'IS NOT NULL') { $qb->andWhere($qb->expr()->isNotNull($filter)); } elseif ($value === 'IS NULL') { diff --git a/lib/Db/Source.php b/lib/Db/Source.php index 1a8b928..09e92ef 100644 --- a/lib/Db/Source.php +++ b/lib/Db/Source.php @@ -37,11 +37,11 @@ public function hydrate(array $object): self { $jsonFields = $this->getJsonFields(); - if(isset($object['metadata']) === false) { + if (isset($object['metadata']) === false) { $object['metadata'] = []; } - foreach($object as $key => $value) { + foreach ($object as $key => $value) { if (in_array($key, $jsonFields) === true && $value === []) { $value = null; } @@ -68,4 +68,4 @@ public function jsonSerialize(): array 'created' => isset($this->created) ? $this->created->format('c') : null ]; } -} \ No newline at end of file +} diff --git a/lib/Db/SourceMapper.php b/lib/Db/SourceMapper.php index 65034c7..67ded28 100644 --- a/lib/Db/SourceMapper.php +++ b/lib/Db/SourceMapper.php @@ -37,7 +37,7 @@ public function findAll(?int $limit = null, ?int $offset = null, ?array $filters ->setMaxResults($limit) ->setFirstResult($offset); - foreach($filters as $filter => $value) { + foreach ($filters as $filter => $value) { if ($value === 'IS NOT NULL') { $qb->andWhere($qb->expr()->isNotNull($filter)); } elseif ($value === 'IS NULL') { diff --git a/lib/Service/SearchService.php b/lib/Service/SearchService.php index ca39445..a5cb602 100644 --- a/lib/Service/SearchService.php +++ b/lib/Service/SearchService.php @@ -28,13 +28,13 @@ public function mergeFacets(array $existingAggregation, array $newAggregation): $existingAggregationMapped = []; $newAggregationMapped = []; - foreach($existingAggregation as $value) { + foreach ($existingAggregation as $value) { $existingAggregationMapped[$value['_id']] = $value['count']; } - foreach($newAggregation as $value) { - if(isset ($existingAggregationMapped[$value['_id']]) === true) { + foreach ($newAggregation as $value) { + if (isset ($existingAggregationMapped[$value['_id']]) === true) { $newAggregationMapped[$value['_id']] = $existingAggregationMapped[$value['_id']] + $value['count']; } else { $newAggregationMapped[$value['_id']] = $value['count']; @@ -52,13 +52,13 @@ public function mergeFacets(array $existingAggregation, array $newAggregation): private function mergeAggregations(?array $existingAggregations, ?array $newAggregations): array { - if($newAggregations === null) { + if ($newAggregations === null) { return []; } - foreach($newAggregations as $key => $aggregation) { - if(isset($existingAggregations[$key]) === false) { + foreach ($newAggregations as $key => $aggregation) { + if (isset($existingAggregations[$key]) === false) { $existingAggregations[$key] = $aggregation; } else { $existingAggregations[$key] = $this->mergeFacets($existingAggregations[$key], $aggregation); @@ -86,7 +86,7 @@ public function search(array $parameters, array $elasticConfig, array $dbConfig, $limit = isset($parameters['.limit']) === true ? $parameters['.limit'] : 30; $page = isset($parameters['.page']) === true ? $parameters['.page'] : 1; - if($elasticConfig['location'] !== '') { + if ($elasticConfig['location'] !== '') { $localResults = $this->elasticService->searchObject(filters: $parameters, config: $elasticConfig, totalResults: $totalResults,); } @@ -94,7 +94,7 @@ public function search(array $parameters, array $elasticConfig, array $dbConfig, // $directory = $this->objectService->findObjects(filters: ['_schema' => 'directory'], config: $dbConfig); - if(count($directory) === 0) { + if (count($directory) === 0) { $pages = (int) ceil($totalResults / $limit); return [ 'results' => $localResults['results'], @@ -114,8 +114,8 @@ public function search(array $parameters, array $elasticConfig, array $dbConfig, $promises = []; - foreach($directory as $instance) { - if( + foreach ($directory as $instance) { + if ( $instance['default'] === false || isset($parameters['.catalogi']) === true && in_array($instance['catalogId'], $parameters['.catalogi']) === false @@ -128,7 +128,7 @@ public function search(array $parameters, array $elasticConfig, array $dbConfig, unset($parameters['.catalogi']); - foreach($searchEndpoints as $searchEndpoint => $catalogi) { + foreach ($searchEndpoints as $searchEndpoint => $catalogi) { $parameters['_catalogi'] = $catalogi; @@ -137,8 +137,8 @@ public function search(array $parameters, array $elasticConfig, array $dbConfig, $responses = Utils::settle($promises)->wait(); - foreach($responses as $response) { - if($response['state'] === 'fulfilled') { + foreach ($responses as $response) { + if ($response['state'] === 'fulfilled') { $responseData = json_decode( json: $response['value']->getBody()->getContents(), associative: true @@ -355,12 +355,12 @@ public function parseQueryString (string $queryString = ''): array { $pairs = explode(separator: '&', string: $queryString); - foreach($pairs as $pair) { + foreach ($pairs as $pair) { $kvpair = explode(separator: '=', string: $pair); $key = urldecode(string: $kvpair[0]); $value = ''; - if(count(value: $kvpair) === 2) { + if (count(value: $kvpair) === 2) { $value = urldecode(string: $kvpair[1]); } From 1a5f0076514a7a9fc4b86b189b7e16bdefb77742 Mon Sep 17 00:00:00 2001 From: Thijn Date: Fri, 4 Oct 2024 16:00:48 +0200 Subject: [PATCH 52/55] added better syncs message --- src/views/object/ObjectDetails.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/views/object/ObjectDetails.vue b/src/views/object/ObjectDetails.vue index 60ed6a2..d767f21 100644 --- a/src/views/object/ObjectDetails.vue +++ b/src/views/object/ObjectDetails.vue @@ -51,15 +51,15 @@ import { objectStore, navigationStore } from '../../store/store.js'
- +

{{ JSON.stringify(objectStore.objectItem.object, null, 2) }}

-

- @todo -

+
+ No synchronizations found +
From 72381dec0ea44fbb6e5ff12bccd591fc62245fb8 Mon Sep 17 00:00:00 2001 From: Robert Zondervan Date: Mon, 14 Oct 2024 17:01:18 +0200 Subject: [PATCH 53/55] Add getRegisters function and enable extending schemas --- lib/Db/SchemaMapper.php | 9 ++ lib/Service/ObjectService.php | 164 +++++++++++++++++++++++++++++++--- 2 files changed, 162 insertions(+), 11 deletions(-) diff --git a/lib/Db/SchemaMapper.php b/lib/Db/SchemaMapper.php index a9f6716..cc43d97 100644 --- a/lib/Db/SchemaMapper.php +++ b/lib/Db/SchemaMapper.php @@ -27,6 +27,15 @@ public function find(int $id): Schema return $this->findEntity(query: $qb); } + public function findMultiple(array $ids): array + { + $result = []; + foreach($ids as $id) { + $result[] = $this->find($id); + } + + return $result; + } public function findAll(?int $limit = null, ?int $offset = null, ?array $filters = [], ?array $searchConditions = [], ?array $searchParams = []): array { diff --git a/lib/Service/ObjectService.php b/lib/Service/ObjectService.php index 1e2cf1e..a80055a 100755 --- a/lib/Service/ObjectService.php +++ b/lib/Service/ObjectService.php @@ -29,7 +29,7 @@ public function __construct(ObjectEntityMapper $objectEntityMapper, RegisterMapp } /** - * Save an object + * Save an object * * @param Register|string $register The register to save the object to. * @param Schema|string $schema The schema to save the object to. @@ -50,14 +50,14 @@ public function saveObject($register, $schema, array $object): ObjectEntity // Does the object already exist? $objectEntity = $this->objectEntityMapper->findByUuid($register, $schema, $object['id']); - + if($objectEntity === null){ $objectEntity = new ObjectEntity(); $objectEntity->setRegister($register->getId()); $objectEntity->setSchema($schema->getId()); ///return $this->objectEntityMapper->update($objectEntity); } - + // Does the object have an if? if (isset($object['id'])) { @@ -82,30 +82,30 @@ public function saveObject($register, $schema, array $object): ObjectEntity throw new \Exception('Unsupported source type'); } - + /** - * Get an object + * Get an object * * @param Register $register The register to save the object to. * @param string $uuid The uuid of the object to get - * + * * @return ObjectEntity The resulting object. */ public function getObject(Register $register, string $uuid): ObjectEntity { // Lets see if we need to save to an internal source if ($register->getSource() === 'internal') { - return $this->objectEntityMapper->findByUuid($register,$uuid); + return $this->objectEntityMapper->findByUuid($register,$uuid); } //@todo mongodb support // Handle external source here if needed throw new \Exception('Unsupported source type'); - } - + } + /** - * Delete an object + * Delete an object * * @param Register $register The register to delete the object from. * @param string $uuid The uuid of the object to delete @@ -116,7 +116,7 @@ public function deleteObject(Register $register, string $uuid) { // Lets see if we need to save to an internal source if ($register->getSource() === 'internal') { - $object = $this->objectEntityMapper->findByUuid($uuid); + $object = $this->objectEntityMapper->findByUuid($uuid); $this->objectEntityMapper->delete($object); } @@ -124,5 +124,147 @@ public function deleteObject(Register $register, string $uuid) // Handle external source here if needed throw new \Exception('Unsupported source type'); + } + + /** + * Gets the appropriate mapper based on the object type. + * + * @param string $objectType The type of object to retrieve the mapper for. + * @return mixed The appropriate mapper. + * @throws \InvalidArgumentException If an unknown object type is provided. + * @throws \Exception If OpenRegister service is not available or if register/schema is not configured. + */ + public function getMapper(string $objectType) + { + // If the source is internal, return the appropriate mapper based on the object type + switch ($objectType) { + case 'register': + return $this->registerMapper; + case 'schema': + return $this->schemaMapper; + case 'objectEntity': + return $this->objectEntityMapper; + default: + throw new \InvalidArgumentException("Unknown object type: $objectType"); + } + } + + /** + * Gets multiple objects based on the object type and ids. + * + * @param string $objectType The type of objects to retrieve. + * @param array $ids The ids of the objects to retrieve. + * @return array The retrieved objects. + * @throws \InvalidArgumentException If an unknown object type is provided. + */ + public function getMultipleObjects(string $objectType, array $ids) + { + // Process the ids + $processedIds = array_map(function($id) { + if (is_object($id) && method_exists($id, 'getId')) { + return $id->getId(); + } elseif (is_array($id) && isset($id['id'])) { + return $id['id']; + } else { + return $id; + } + }, $ids); + + // Clean up the ids if they are URIs + $cleanedIds = array_map(function($id) { + // If the id is a URI, get only the last part of the path + if (filter_var($id, FILTER_VALIDATE_URL)) { + $parts = explode('/', rtrim($id, '/')); + return end($parts); + } + return $id; + }, $processedIds); + + // Get the appropriate mapper for the object type + $mapper = $this->getMapper($objectType); + + // Use the mapper to find and return multiple objects based on the provided cleaned ids + return $mapper->findMultiple($cleanedIds); + } + + /** + * Extends an entity with related objects based on the extend array. + * + * @param mixed $entity The entity to extend + * @param array $extend An array of properties to extend + * @return array The extended entity as an array + * @throws \Exception If a property is not present on the entity + */ + public function extendEntity(array $entity, array $extend): array + { + // Convert the entity to an array if it's not already one + $result = is_array($entity) ? $entity : $entity->jsonSerialize(); + + // Iterate through each property to be extended + foreach ($extend as $property) { + // Create a singular property name + $singularProperty = rtrim($property, 's'); + + // Check if property or singular property are keys in the array + if (array_key_exists($property, $result)) { + $value = $result[$property]; + if (empty($value)) { + continue; + } + } elseif (array_key_exists($singularProperty, $result)) { + $value = $result[$singularProperty]; + } else { + throw new \Exception("Property '$property' or '$singularProperty' is not present in the entity."); + } + + // Get a mapper for the property + $propertyObject = $property; + try { + $mapper = $this->getMapper($property); + $propertyObject = $singularProperty; + } catch (\Exception $e) { + try { + $mapper = $this->getMapper($singularProperty); + $propertyObject = $singularProperty; + } catch (\Exception $e) { + // If still no mapper, throw a no mapper available error + throw new \Exception("No mapper available for property '$property'."); + } + } + + // Update the values + if (is_array($value)) { + // If the value is an array, get multiple related objects + $result[$property] = $this->getMultipleObjects($propertyObject, $value); + } else { + // If the value is not an array, get a single related object + $objectId = is_object($value) ? $value->getId() : $value; + $result[$property] = $mapper->find($objectId); + } + } + + // Return the extended entity as an array + return $result; + } + + public function getRegisters(): array + { + $registers = $this->registerMapper->findAll(); + + + // Convert entity objects to arrays using jsonSerialize + $registers = array_map(function($object) { + return $object->jsonSerialize(); + }, $registers); + + $extend = ['schemas']; + // Extend the objects if the extend array is not empty + if(!empty($extend)) { + $registers = array_map(function($object) use ($extend) { + return $this->extendEntity($object, $extend); + }, $registers); + } + + return $registers; } } From 6d5d8f36f29ded26d5e2f84cca2e66a8b9d04962 Mon Sep 17 00:00:00 2001 From: Robert Zondervan Date: Tue, 15 Oct 2024 09:15:21 +0200 Subject: [PATCH 54/55] Style fixes for PR review --- lib/Service/ObjectService.php | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/Service/ObjectService.php b/lib/Service/ObjectService.php index a80055a..2911d17 100755 --- a/lib/Service/ObjectService.php +++ b/lib/Service/ObjectService.php @@ -198,7 +198,11 @@ public function getMultipleObjects(string $objectType, array $ids) public function extendEntity(array $entity, array $extend): array { // Convert the entity to an array if it's not already one - $result = is_array($entity) ? $entity : $entity->jsonSerialize(); + if(is_array($entity)) { + $result = $entity; + } else { + $result = $entity->jsonSerialize(); + } // Iterate through each property to be extended foreach ($extend as $property) { @@ -206,12 +210,12 @@ public function extendEntity(array $entity, array $extend): array $singularProperty = rtrim($property, 's'); // Check if property or singular property are keys in the array - if (array_key_exists($property, $result)) { + if (array_key_exists(key: $property, array: $result) === true) { $value = $result[$property]; if (empty($value)) { continue; } - } elseif (array_key_exists($singularProperty, $result)) { + } elseif (array_key_exists(key: $singularProperty, array: $result)) { $value = $result[$singularProperty]; } else { throw new \Exception("Property '$property' or '$singularProperty' is not present in the entity."); @@ -220,25 +224,25 @@ public function extendEntity(array $entity, array $extend): array // Get a mapper for the property $propertyObject = $property; try { - $mapper = $this->getMapper($property); + $mapper = $this->getMapper(objectType: $property); $propertyObject = $singularProperty; } catch (\Exception $e) { try { - $mapper = $this->getMapper($singularProperty); + $mapper = $this->getMapper(objectType: $singularProperty); $propertyObject = $singularProperty; } catch (\Exception $e) { // If still no mapper, throw a no mapper available error - throw new \Exception("No mapper available for property '$property'."); + throw new \Exception(message: "No mapper available for property '$property'."); } } // Update the values - if (is_array($value)) { + if (is_array($value) === true) { // If the value is an array, get multiple related objects - $result[$property] = $this->getMultipleObjects($propertyObject, $value); + $result[$property] = $this->getMultipleObjects(objectType: $propertyObject, ids: $value); } else { // If the value is not an array, get a single related object - $objectId = is_object($value) ? $value->getId() : $value; + $objectId = is_object(value: $value) ? $value->getId() : $value; $result[$property] = $mapper->find($objectId); } } @@ -247,6 +251,12 @@ public function extendEntity(array $entity, array $extend): array return $result; } + /** + * Get the registers extended with schemas for this instance of OpenRegisters + * + * @return array The registers of this OpenRegisters instance extended with schemas + * @throws \Exception + */ public function getRegisters(): array { $registers = $this->registerMapper->findAll(); @@ -259,9 +269,9 @@ public function getRegisters(): array $extend = ['schemas']; // Extend the objects if the extend array is not empty - if(!empty($extend)) { + if(empty($extend) === false) { $registers = array_map(function($object) use ($extend) { - return $this->extendEntity($object, $extend); + return $this->extendEntity(entity: $object, extend: $extend); }, $registers); } From 948b78636ccd6b25d3a85f0170085be761cccc09 Mon Sep 17 00:00:00 2001 From: Remko Date: Tue, 15 Oct 2024 15:52:44 +0200 Subject: [PATCH 55/55] Add schema fix --- src/entities/schema/schema.ts | 3 --- src/entities/schema/schema.types.ts | 1 - src/modals/schema/EditSchema.vue | 1 - 3 files changed, 5 deletions(-) diff --git a/src/entities/schema/schema.ts b/src/entities/schema/schema.ts index 04d5654..4239d09 100644 --- a/src/entities/schema/schema.ts +++ b/src/entities/schema/schema.ts @@ -11,7 +11,6 @@ export class Schema implements TSchema { public required: string[] public properties: Record public archive: Record - public source: string public updated: string public created: string @@ -24,7 +23,6 @@ export class Schema implements TSchema { this.required = schema.required || [] this.properties = schema.properties || {} this.archive = schema.archive || {} - this.source = schema.source || '' this.updated = schema.updated || '' this.created = schema.created || '' } @@ -39,7 +37,6 @@ export class Schema implements TSchema { required: z.array(z.string()), properties: z.object({}), archive: z.object({}), - source: z.string(), updated: z.string(), created: z.string(), }) diff --git a/src/entities/schema/schema.types.ts b/src/entities/schema/schema.types.ts index 4d3dbdf..74d500f 100644 --- a/src/entities/schema/schema.types.ts +++ b/src/entities/schema/schema.types.ts @@ -7,7 +7,6 @@ export type TSchema = { required: string[] properties: Record archive: Record - source: string updated: string; created: string; } diff --git a/src/modals/schema/EditSchema.vue b/src/modals/schema/EditSchema.vue index a238f89..a1296fd 100644 --- a/src/modals/schema/EditSchema.vue +++ b/src/modals/schema/EditSchema.vue @@ -127,7 +127,6 @@ export default { version: '', description: '', summary: '', - source: '', created: '', updated: '', }