diff --git a/.github/workflows/pull-request-from-branch-check.yaml b/.github/workflows/pull-request-from-branch-check.yaml new file mode 100644 index 0000000..77d1970 --- /dev/null +++ b/.github/workflows/pull-request-from-branch-check.yaml @@ -0,0 +1,18 @@ +name: Main Branch Protection + +on: + pull_request: + branches: + - main + +jobs: + check-branch: + runs-on: ubuntu-latest + steps: + - name: Check branch + run: | + if [[ ${GITHUB_HEAD_REF} != development ]] && [[ ${GITHUB_HEAD_REF} != documentation ]] && ! [[ ${GITHUB_HEAD_REF} =~ ^hotfix/ ]]; + then + echo "Error: Pull request must come from 'development', 'documentation' or 'hotfix/' branch" + exit 1 + fi diff --git a/.github/workflows/pull-request-lint-check.yaml b/.github/workflows/pull-request-lint-check.yaml new file mode 100644 index 0000000..4a8c874 --- /dev/null +++ b/.github/workflows/pull-request-lint-check.yaml @@ -0,0 +1,21 @@ +name: Lint Check + +on: + pull_request: + branches: + - development + - main + +jobs: + lint-check: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install dependencies + run: npm i + + - name: Linting + run: npm run lint diff --git a/appinfo/routes.php b/appinfo/routes.php index 9567c1a..307a966 100755 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -11,6 +11,8 @@ ['name' => 'dashboard#page', 'url' => '/', 'verb' => 'GET'], ['name' => 'registers#objects', 'url' => '/api/registers-objects/{register}/{schema}', 'verb' => 'GET'], ['name' => 'objects#logs', 'url' => '/api/objects-logs/{id}', 'verb' => 'GET', 'requirements' => ['id' => '[^/]+']], + ['name' => 'objects#mappings', 'url' => '/api/objects/mappings', 'verb' => 'GET'], + ['name' => 'objects#auditTrails', 'url' => '/api/objects/audit-trails/{id}', 'verb' => 'GET', 'requirements' => ['id' => '[^/]+']], ['name' => 'schemas#upload', 'url' => '/api/schemas/upload', 'verb' => 'POST'], ['name' => 'schemas#uploadUpdate', 'url' => '/api/schemas/{id}/upload', 'verb' => 'PUT', 'requirements' => ['id' => '[^/]+']], ['name' => 'schemas#download', 'url' => '/api/schemas/{id}/download', 'verb' => 'GET', 'requirements' => ['id' => '[^/]+']], diff --git a/docker-compose.yml b/docker-compose.yml index 375daca..20bbdf0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -47,3 +47,6 @@ services: - TZ=Europe/Amsterdam - NEXTCLOUD_ADMIN_USER=admin - NEXTCLOUD_ADMIN_PASSWORD=admin + depends_on: + init-ubuntu: + condition: service_completed_successfully diff --git a/lib/Controller/ObjectsController.php b/lib/Controller/ObjectsController.php index 12da7d9..f5fc177 100644 --- a/lib/Controller/ObjectsController.php +++ b/lib/Controller/ObjectsController.php @@ -13,9 +13,13 @@ use OCP\AppFramework\Http\JSONResponse; use OCP\DB\Exception; use OCP\IAppConfig; -use OCP\IRequest; +use OCP\IRequest; +use OCP\App\IAppManager; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; use Opis\JsonSchema\Errors\ErrorFormatter; use Symfony\Component\Uid\Uuid; +use Psr\Container\ContainerInterface; class ObjectsController extends Controller { @@ -32,6 +36,8 @@ public function __construct( $appName, IRequest $request, private readonly IAppConfig $config, + private readonly IAppManager $appManager, + private readonly ContainerInterface $container, private readonly ObjectEntityMapper $objectEntityMapper, private readonly AuditTrailMapper $auditTrailMapper, private readonly ObjectAuditLogMapper $objectAuditLogMapper @@ -111,20 +117,24 @@ public function show(string $id): JSONResponse } } - /** - * Creates a new object - * - * This method creates a new object based on POST data. - * - * @NoAdminRequired - * @NoCSRFRequired - * - * @return JSONResponse A JSON response containing the created object - */ + /** + * Creates a new object + * + * This method creates a new object based on POST data. + * + * @NoAdminRequired + * @NoCSRFRequired + * + * @return JSONResponse A JSON response containing the created object + * @throws Exception + */ public function create(ObjectService $objectService): JSONResponse { $data = $this->request->getParams(); $object = $data['object']; + $mapping = $data['mapping'] ?? null; + $register = $data['register']; + $schema = $data['schema']; foreach ($data as $key => $value) { if (str_starts_with($key, '_')) { @@ -136,6 +146,17 @@ public function create(ObjectService $objectService): JSONResponse unset($data['id']); } + // If mapping ID is provided, transform the object using the mapping + $mappingService = $this->getOpenConnectorMappingService(); + + if ($mapping !== null && $mappingService !== null) { + $mapping = $mappingService->getMapping($mapping); + + $object = $mappingService->executeMapping($mapping, $object); + $data['register'] = $register; + $data['schema'] = $schema; + } + // Save the object try { $objectEntity = $objectService->saveObject(register: $data['register'], schema: $data['schema'], object: $object); @@ -163,6 +184,7 @@ public function update(int $id): JSONResponse { $data = $this->request->getParams(); $object = $data['object']; + $mapping = $data['mapping'] ?? null; foreach ($data as $key => $value) { if (str_starts_with($key, '_')) { @@ -173,6 +195,14 @@ public function update(int $id): JSONResponse unset($data['id']); } + // If mapping ID is provided, transform the object using the mapping + $mappingService = $this->getOpenConnectorMappingService(); + + if ($mapping !== null && $mappingService !== null) { + $mapping = $mappingService->getMapping($mapping); + $data = $mappingService->executeMapping($mapping, $object); + } + // save it $oldObject = $this->objectEntityMapper->find($id); $objectEntity = $this->objectEntityMapper->updateFromArray(id: $id, object: $data); @@ -265,4 +295,57 @@ public function logs(int $id): JSONResponse return new JSONResponse(['error' => 'Logs not found'], 404); } } + + + + /** + * Retrieves all available mappings + * + * This method returns a JSON response containing all available mappings in the system. + * + * @NoAdminRequired + * @NoCSRFRequired + * + * @return JSONResponse A JSON response containing the list of mappings + */ + public function mappings(): JSONResponse + { + // Get mapping service, which will return null based on implementation + $mappingService = $this->getOpenConnectorMappingService(); + + // Initialize results array + $results = []; + + // If mapping service exists, get all mappings using find() method + if ($mappingService !== null) { + $results = $mappingService->getMappings(); + } + + // Return response with results array and total count + return new JSONResponse([ + 'results' => $results, + 'total' => count($results) + ]); + } + + /** + * Attempts to retrieve the OpenRegister service from the container. + * + * @return mixed|null The OpenRegister service if available, null otherwise. + * @throws ContainerExceptionInterface|NotFoundExceptionInterface + */ + public function getOpenConnectorMappingService(): ?\OCA\OpenConnector\Service\MappingService + { + if (in_array(needle: 'openconnector', haystack: $this->appManager->getInstalledApps()) === true) { + try { + // Attempt to get the OpenRegister service from the container + return $this->container->get('OCA\OpenConnector\Service\MappingService'); + } catch (Exception $e) { + // If the service is not available, return null + return null; + } + } + + return null; + } } diff --git a/lib/Db/ObjectEntityMapper.php b/lib/Db/ObjectEntityMapper.php index a883fba..a64af65 100644 --- a/lib/Db/ObjectEntityMapper.php +++ b/lib/Db/ObjectEntityMapper.php @@ -16,7 +16,7 @@ /** * The ObjectEntityMapper class - * + * * @package OCA\OpenRegister\Db */ class ObjectEntityMapper extends QBMapper @@ -35,7 +35,7 @@ public function __construct(IDBConnection $db, MySQLJsonService $mySQLJsonServic { parent::__construct($db, 'openregister_objects'); - if($db->getDatabasePlatform() instanceof MySQLPlatform === true) { + if ($db->getDatabasePlatform() instanceof MySQLPlatform === true) { $this->databaseJsonService = $mySQLJsonService; } } @@ -235,15 +235,15 @@ public function updateFromArray(int $id, array $object): ObjectEntity */ public function getFacets(array $filters = [], ?string $search = null) { - if(key_exists(key: 'register', array: $filters) === true) { + if (key_exists(key: 'register', array: $filters) === true) { $register = $filters['register']; } - if(key_exists(key: 'schema', array: $filters) === true) { + if (key_exists(key: 'schema', array: $filters) === true) { $schema = $filters['schema']; } $fields = []; - if(isset($filters['_queries'])) { + if (isset($filters['_queries'])) { $fields = $filters['_queries']; } diff --git a/lib/Db/SchemaMapper.php b/lib/Db/SchemaMapper.php index 2ca6725..2b83986 100644 --- a/lib/Db/SchemaMapper.php +++ b/lib/Db/SchemaMapper.php @@ -11,7 +11,7 @@ /** * The SchemaMapper class - * + * * @package OCA\OpenRegister\Db */ class SchemaMapper extends QBMapper @@ -54,7 +54,7 @@ public function find(int $id): Schema public function findMultiple(array $ids): array { $result = []; - foreach($ids as $id) { + foreach ($ids as $id) { $result[] = $this->find($id); } @@ -116,7 +116,7 @@ public function createFromArray(array $object): Schema if ($schema->getUuid() === null) { $schema->setUuid(Uuid::v4()); } - + return $this->insert(entity: $schema); } diff --git a/lib/Service/MySQLJsonService.php b/lib/Service/MySQLJsonService.php index f0ff964..3331ef1 100644 --- a/lib/Service/MySQLJsonService.php +++ b/lib/Service/MySQLJsonService.php @@ -7,7 +7,7 @@ /** * Service class for handling MySQL JSON operations - * + * * This class provides methods for querying and filtering JSON data stored in MySQL, * including complex filtering, searching, ordering and aggregation functionality. */ @@ -23,7 +23,7 @@ class MySQLJsonService implements IDatabaseJsonService public function orderJson(IQueryBuilder $builder, array $order = []): IQueryBuilder { // Loop through each ordering field and direction - foreach($order as $item=>$direction) { + foreach ($order as $item=>$direction) { // Create parameters for the JSON path and sort direction $builder->createNamedParameter(value: "$.$item", placeHolder: ":path$item"); $builder->createNamedParameter(value: $direction, placeHolder: ":direction$item"); @@ -108,7 +108,7 @@ private function jsonFilterArray(IQueryBuilder $builder, string $filter, array $ private function getMultipleContains (array $values, string $filter, IQueryBuilder $builder): string { $orString = ''; - foreach($values as $key=>$value) + foreach ($values as $key=>$value) { // Create parameter for each value $builder->createNamedParameter(value: $value, type: IQueryBuilder::PARAM_STR, placeHolder: ":value$filter$key"); @@ -126,7 +126,7 @@ private function getMultipleContains (array $values, string $filter, IQueryBuild * - Complex filters (after/before) * - Array filters * - Simple equality filters - * + * * @param IQueryBuilder $builder The query builder instance * @param array $filters Array of filters to apply * @return IQueryBuilder The modified query builder @@ -136,7 +136,7 @@ public function filterJson(IQueryBuilder $builder, array $filters): IQueryBuilde // Remove special system fields from filters unset($filters['register'], $filters['schema'], $filters['updated'], $filters['created'], $filters['_queries']); - foreach($filters as $filter=>$value) { + foreach ($filters as $filter=>$value) { // Create parameter for JSON path $builder->createNamedParameter(value: "$.$filter", placeHolder: ":path$filter"); @@ -179,7 +179,7 @@ public function getAggregations(IQueryBuilder $builder, array $fields, int $regi { $facets = []; - foreach($fields as $field) { + foreach ($fields as $field) { // Create parameter for JSON path $builder->createNamedParameter(value: "$.$field", placeHolder: ":$field"); diff --git a/lib/Service/ObjectService.php b/lib/Service/ObjectService.php index 90d5113..7be4d13 100755 --- a/lib/Service/ObjectService.php +++ b/lib/Service/ObjectService.php @@ -15,6 +15,7 @@ use OCA\OpenRegister\Db\AuditTrailMapper; use OCA\OpenRegister\Exception\ValidationException; use OCA\OpenRegister\Formats\BsnFormat; +use OCP\DB\Exception; use OCP\IURLGenerator; use Opis\JsonSchema\ValidationResult; use Opis\JsonSchema\Validator; @@ -24,20 +25,20 @@ /** * Service class for handling object operations - * + * * This service provides methods for CRUD operations on objects, including: * - Creating, reading, updating and deleting objects * - Finding objects by ID/UUID * - Getting audit trails * - Extending objects with related data - * + * * @package OCA\OpenRegister\Service */ class ObjectService { /** @var int The current register ID */ private int $register; - + /** @var int The current schema ID */ private int $schema; @@ -58,7 +59,8 @@ public function __construct( ObjectEntityMapper $objectEntityMapper, RegisterMapper $registerMapper, SchemaMapper $schemaMapper, - AuditTrailMapper $auditTrailMapper + AuditTrailMapper $auditTrailMapper, + private readonly IURLGenerator $urlGenerator ) { $this->objectEntityMapper = $objectEntityMapper; @@ -67,7 +69,31 @@ public function __construct( $this->auditTrailMapper = $auditTrailMapper; } - /** + /** + * Validate an object with a schema. + * If schema is not given and schemaObject is filled, the object will validate to the schemaObject. + * + * @param array $object The object to validate. + * @param int|null $schemaId The id of the schema to validate to. + * @param object $schemaObject A schema object to validate to. + * + * @return ValidationResult The validation result from opis/json-schema. + */ + public function validateObject(array $object, ?int $schemaId = null, object $schemaObject = new stdClass()): ValidationResult + { + if ($schemaObject === new stdClass() || $schemaId !== null) { + $schemaObject = $this->schemaMapper->find($schemaId)->getSchemaObject($this->urlGenerator); + } + + $validator = new Validator(); + $validator->setMaxErrors(100); + $validator->parser()->getFormatResolver()->register('string', 'bsn', new BsnFormat()); + + return $validator->validate(data: json_decode(json_encode($object)), schema: $schemaObject); + + } + + /** * Find an object by ID or UUID * * @param int|string $id The ID or UUID to search for @@ -123,7 +149,7 @@ public function updateFromArray(string $id, array $object, bool $updatedObject) public function delete(array|\JsonSerializable $object): bool { // Convert JsonSerializable objects to array - if($object instanceof \JsonSerializable === true) { + if ($object instanceof \JsonSerializable === true) { $object = $object->jsonSerialize(); } @@ -169,11 +195,11 @@ public function findAll(?int $limit = null, ?int $offset = null, array $filters public function count(array $filters = [], ?string $search = null): int { // Add register and schema filters if set - if($this->getSchema() !== null && $this->getRegister() !== null) { + if ($this->getSchema() !== null && $this->getRegister() !== null) { $filters['register'] = $this->getRegister(); $filters['schema'] = $this->getSchema(); } - + return $this->objectEntityMapper ->countAll(filters: $filters, search: $search); } @@ -187,7 +213,7 @@ public function count(array $filters = [], ?string $search = null): int public function findMultiple(array $ids): array { $result = []; - foreach($ids as $id) { + foreach ($ids as $id) { $result[] = $this->find($id); } @@ -242,7 +268,7 @@ private function getDataFromObject(mixed $object) { public function getObjects(?string $objectType = null, ?int $register = null, ?int $schema = null, ?int $limit = null, ?int $offset = null, array $filters = [], array $sort = [], ?string $search = null): array { // Set object type and filters if register and schema are provided - if($objectType === null && $register !== null && $schema !== null) { + if ($objectType === null && $register !== null && $schema !== null) { $objectType = 'objectEntity'; $filters['register'] = $register; $filters['schema'] = $schema; @@ -255,15 +281,17 @@ public function getObjects(?string $objectType = null, ?int $register = null, ?i return $mapper->findAll(limit: $limit, offset: $offset, filters: $filters, sort: $sort, search: $search); } - /** - * 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. - * @param array $object The data to be saved. - * - * @return ObjectEntity The resulting object. - */ + /** + * Save an object + * + * @param int $register The register to save the object to. + * @param int $schema The schema to save the object to. + * @param array $object The data to be saved. + * + * @return ObjectEntity The resulting object. + * @throws ValidationException When the validation fails and returns an error. + * @throws Exception + */ public function saveObject(int $register, int $schema, array $object): ObjectEntity { // Convert register and schema to their respective objects if they are strings @@ -275,16 +303,18 @@ public function saveObject(int $register, int $schema, array $object): ObjectEnt } // Check if object already exists - if(isset($object['id']) === true) { + if (isset($object['id']) === true) { $objectEntity = $this->objectEntityMapper->findByUuid( - $this->registerMapper->find($register), - $this->schemaMapper->find($schema), + $this->registerMapper->find($register), + $this->schemaMapper->find($schema), $object['id'] ); } + $validationResult = $this->validateObject(object: $object, schemaId: $schema); + // Create new entity if none exists - if($objectEntity === null){ + if ($objectEntity === null) { $objectEntity = new ObjectEntity(); $objectEntity->setRegister($register); $objectEntity->setSchema($schema); @@ -301,21 +331,25 @@ public function saveObject(int $register, int $schema, array $object): ObjectEnt // Store old version for audit trail $oldObject = clone $objectEntity; $objectEntity->setObject($object); - + // Ensure UUID exists if (empty($objectEntity->getUuid())) { $objectEntity->setUuid(Uuid::v4()); } - // Update or insert based on whether ID exists - if($objectEntity->getId()){ - $objectEntity = $this->objectEntityMapper->update($objectEntity); - $this->auditTrailMapper->createAuditTrail(new: $objectEntity, old: $oldObject); - } - else { - $objectEntity = $this->objectEntityMapper->insert($objectEntity); - $this->auditTrailMapper->createAuditTrail(new: $objectEntity); - } + $schemaObject = $this->schemaMapper->find($schema); + + if ($objectEntity->getId() && ($schemaObject->getHardValidation() === false || $validationResult->isValid() === true)){ + $objectEntity = $this->objectEntityMapper->update($objectEntity); + $this->auditTrailMapper->createAuditTrail(new: $objectEntity, old: $oldObject); + } else if ($schemaObject->getHardValidation() === false || $validationResult->isValid() === true) { + $objectEntity = $this->objectEntityMapper->insert($objectEntity); + $this->auditTrailMapper->createAuditTrail(new: $objectEntity); + } + + if ($validationResult->isValid() === false) { + throw new ValidationException(message: 'The object could not be validated', errors: $validationResult->error()); + } return $objectEntity; } @@ -378,7 +412,7 @@ public function deleteObject(Register $register, Schema $schema, string $uuid): public function getMapper(?string $objectType = null, ?int $register = null, ?int $schema = null) { // Return self if register and schema provided - if($register !== null && $schema !== null) { + if ($register !== null && $schema !== null) { $this->setSchema($schema); $this->setRegister($register); return $this; @@ -443,7 +477,7 @@ public function getMultipleObjects(string $objectType, array $ids) public function extendEntity(array $entity, array $extend): array { // Convert entity to array if needed - if(is_array($entity)) { + if (is_array($entity)) { $result = $entity; } else { $result = $entity->jsonSerialize(); @@ -509,7 +543,7 @@ public function getRegisters(): array // Extend with schemas $extend = ['schemas']; - if(empty($extend) === false) { + if (empty($extend) === false) { $registers = array_map(function($object) use ($extend) { return $this->extendEntity(entity: $object, extend: $extend); }, $registers); diff --git a/package-lock.json b/package-lock.json index 3d59b6b..551c1c9 100755 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,6 @@ "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-codemirror6": "^1.3.4", @@ -21213,18 +21212,6 @@ "node": ">= 0.4.0" } }, - "node_modules/uuid": { - "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" - } - }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", @@ -37943,11 +37930,6 @@ "dev": true, "peer": true }, - "uuid": { - "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", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", diff --git a/package.json b/package.json index 5fae2c2..d199420 100755 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "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-codemirror6": "^1.3.4", diff --git a/src/entities/auditTrail/index.js b/src/entities/auditTrail/index.js index 98de241..b49eb51 100644 --- a/src/entities/auditTrail/index.js +++ b/src/entities/auditTrail/index.js @@ -1,4 +1,3 @@ export * from './auditTrail.ts' export * from './auditTrail.types.ts' export * from './auditTrail.mock.ts' - diff --git a/src/entities/schema/schema.ts b/src/entities/schema/schema.ts index 4239d09..4dcd6d9 100644 --- a/src/entities/schema/schema.ts +++ b/src/entities/schema/schema.ts @@ -31,7 +31,7 @@ export class Schema implements TSchema { const schema = z.object({ id: z.string().min(1), title: z.string().min(1), - version: z.string(), + version: z.string().regex(/^(?:\d+\.){2}\d+$/g, 'Invalid version format'), description: z.string(), summary: z.string(), required: z.array(z.string()), diff --git a/src/modals/Modals.vue b/src/modals/Modals.vue index 3bb513b..fc22305 100755 --- a/src/modals/Modals.vue +++ b/src/modals/Modals.vue @@ -8,15 +8,16 @@ import { navigationStore } from '../store/store.js' - + - + + @@ -34,6 +35,7 @@ import EditSource from './source/EditSource.vue' import DeleteSource from './source/DeleteSource.vue' import EditObject from './object/EditObject.vue' import DeleteObject from './object/DeleteObject.vue' +import UploadObject from './object/UploadObject.vue' import ViewObjectAuditTrail from './objectAuditTrail/ViewObjectAuditTrail.vue' export default { @@ -51,6 +53,7 @@ export default { DeleteSource, EditObject, DeleteObject, + UploadObject, ViewObjectAuditTrail, }, } diff --git a/src/modals/object/DeleteObject.vue b/src/modals/object/DeleteObject.vue index 235983d..969c27b 100644 --- a/src/modals/object/DeleteObject.vue +++ b/src/modals/object/DeleteObject.vue @@ -67,11 +67,13 @@ export default { success: null, loading: false, error: false, + closeModalTimeout: null, } }, methods: { closeDialog() { navigationStore.setDialog(false) + clearTimeout(this.closeModalTimeout) this.success = null this.loading = false this.error = false @@ -84,7 +86,7 @@ export default { }).then(({ response }) => { this.success = response.ok this.error = false - response.ok && setTimeout(this.closeDialog, 2000) + response.ok && (this.closeModalTimeout = setTimeout(this.closeDialog, 2000)) }).catch((error) => { this.success = false this.error = error.message || 'An error occurred while deleting the object' diff --git a/src/modals/object/EditObject.vue b/src/modals/object/EditObject.vue index dae8b52..094d372 100644 --- a/src/modals/object/EditObject.vue +++ b/src/modals/object/EditObject.vue @@ -140,6 +140,7 @@ export default { loading: false, error: false, hasUpdated: false, + closeModalTimeout: null, } }, mounted() { @@ -220,6 +221,7 @@ export default { }, closeModal() { navigationStore.setModal(false) + clearTimeout(this.closeModalTimeout) this.success = null this.loading = false this.error = false @@ -241,7 +243,7 @@ export default { }).then(({ response }) => { this.success = response.ok this.error = false - response.ok && setTimeout(this.closeModal, 2000) + response.ok && (this.closeModalTimeout = setTimeout(this.closeModal, 2000)) }).catch((error) => { this.success = false this.error = error.message || 'An error occurred while saving the object' diff --git a/src/modals/object/UploadObject.vue b/src/modals/object/UploadObject.vue new file mode 100644 index 0000000..006dcad --- /dev/null +++ b/src/modals/object/UploadObject.vue @@ -0,0 +1,304 @@ + + + + + + + diff --git a/src/modals/register/DeleteRegister.vue b/src/modals/register/DeleteRegister.vue index 7963ccb..6d246e7 100644 --- a/src/modals/register/DeleteRegister.vue +++ b/src/modals/register/DeleteRegister.vue @@ -8,7 +8,7 @@ import { registerStore, navigationStore } from '../../store/store.js' size="normal" :can-close="false">

- Wil je {{ registerStore.registerItem.title }} definitief verwijderen? Deze actie kan niet ongedaan worden gemaakt. + Wil je {{ registerStore.registerItem?.title }} definitief verwijderen? Deze actie kan niet ongedaan worden gemaakt.

@@ -67,11 +67,13 @@ export default { success: false, loading: false, error: false, + closeModalTimeout: null, } }, methods: { closeDialog() { navigationStore.setDialog(false) + clearTimeout(this.closeModalTimeout) this.success = false this.loading = false this.error = false @@ -84,7 +86,7 @@ export default { }).then(({ response }) => { this.success = response.ok this.error = false - response.ok && setTimeout(this.closeDialog, 2000) + response.ok && (this.closeModalTimeout = setTimeout(this.closeDialog, 2000)) }).catch((error) => { this.success = false this.error = error.message || 'Er is een fout opgetreden bij het verwijderen van het register' diff --git a/src/modals/register/EditRegister.vue b/src/modals/register/EditRegister.vue index 6392d53..7d9c3ed 100644 --- a/src/modals/register/EditRegister.vue +++ b/src/modals/register/EditRegister.vue @@ -107,6 +107,7 @@ export default { loading: false, error: false, hasUpdated: false, + closeModalTimeout: null, } }, mounted() { @@ -193,6 +194,7 @@ export default { }, closeModal() { navigationStore.setModal(false) + clearTimeout(this.closeModalTimeout) this.success = null this.loading = false this.error = false @@ -217,7 +219,7 @@ export default { }).then(({ response }) => { this.success = response.ok this.error = false - response.ok && setTimeout(this.closeModal, 2000) + response.ok && (this.closeModalTimeout = setTimeout(this.closeModal, 2000)) }).catch((error) => { this.success = false this.error = error.message || 'An error occurred while saving the register' diff --git a/src/modals/register/UploadRegister.vue b/src/modals/register/UploadRegister.vue index 9467f4e..6f1b323 100644 --- a/src/modals/register/UploadRegister.vue +++ b/src/modals/register/UploadRegister.vue @@ -52,10 +52,8 @@ import { NcTextArea, NcLoadingIcon, NcNoteCard, - NcSelect, } from '@nextcloud/vue' -import ContentSaveOutline from 'vue-material-design-icons/ContentSaveOutline.vue' import Cancel from 'vue-material-design-icons/Cancel.vue' import Upload from 'vue-material-design-icons/Upload.vue' @@ -68,9 +66,7 @@ export default { NcButton, NcLoadingIcon, NcNoteCard, - NcSelect, // Icons - ContentSaveOutline, Cancel, Upload, }, @@ -78,24 +74,26 @@ export default { return { register: { json: '{}', - url: '' + url: '', }, success: false, loading: false, error: false, hasUpdated: false, + closeModalTimeout: null, } }, methods: { closeModal() { navigationStore.setModal(false) + clearTimeout(this.closeModalTimeout) this.success = null this.loading = false this.error = false this.hasUpdated = false this.register = { json: '{}', - url: '' + url: '', } }, async uploadRegister() { @@ -104,7 +102,7 @@ export default { registerStore.uploadRegister(this.register).then(({ response }) => { this.success = response.ok this.error = false - response.ok && setTimeout(this.closeModal, 2000) + response.ok && (this.closeModalTimeout = setTimeout(this.closeModal, 2000)) }).catch((error) => { this.success = false this.error = error.message || 'An error occurred while uploading the register' diff --git a/src/modals/schema/DeleteSchema.vue b/src/modals/schema/DeleteSchema.vue index 080b078..d667815 100644 --- a/src/modals/schema/DeleteSchema.vue +++ b/src/modals/schema/DeleteSchema.vue @@ -8,7 +8,7 @@ import { schemaStore, navigationStore } from '../../store/store.js' size="normal" :can-close="false">

- Do you want to permanently delete {{ schemaStore.schemaItem.title }}? This action cannot be undone. + Do you want to permanently delete {{ schemaStore.schemaItem?.title }}? This action cannot be undone.

@@ -67,11 +67,13 @@ export default { success: false, loading: false, error: false, + closeModalTimeout: null, } }, methods: { closeDialog() { navigationStore.setDialog(false) + clearTimeout(this.closeModalTimeout) this.success = false this.loading = false this.error = false @@ -84,7 +86,7 @@ export default { }).then(({ response }) => { this.success = response.ok this.error = false - response.ok && setTimeout(this.closeDialog, 2000) + response.ok && (this.closeModalTimeout = setTimeout(this.closeDialog, 2000)) }).catch((error) => { this.success = false this.error = error.message || 'An error occurred while deleting the schema' diff --git a/src/modals/schema/DeleteSchemaProperty.vue b/src/modals/schema/DeleteSchemaProperty.vue index 4caf685..fc1fae5 100644 --- a/src/modals/schema/DeleteSchemaProperty.vue +++ b/src/modals/schema/DeleteSchemaProperty.vue @@ -24,7 +24,7 @@ import { navigationStore, schemaStore } from '../../store/store.js'