diff --git a/dbrepo-metadata-db/api/src/main/java/at/tuwien/api/database/table/columns/ColumnBriefDto.java b/dbrepo-metadata-db/api/src/main/java/at/tuwien/api/database/table/columns/ColumnBriefDto.java index 38ba0bff019836a9b00f128a75004740139dd385..7863806cb538886c81db162729493ad7d85b7888 100644 --- a/dbrepo-metadata-db/api/src/main/java/at/tuwien/api/database/table/columns/ColumnBriefDto.java +++ b/dbrepo-metadata-db/api/src/main/java/at/tuwien/api/database/table/columns/ColumnBriefDto.java @@ -1,5 +1,6 @@ package at.tuwien.api.database.table.columns; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; @@ -20,6 +21,14 @@ public class ColumnBriefDto { @NotNull(message = "id is required") private Long id; + @JsonProperty("database_id") + @NotNull(message = "database id is required") + private Long databaseId; + + @JsonProperty("table_id") + @NotNull(message = "table id is required") + private Long tableId; + @NotBlank(message = "name is required") @Schema(example = "date") private String name; diff --git a/dbrepo-metadata-db/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptDto.java b/dbrepo-metadata-db/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptDto.java index 68b98535aacb462719a1b08f245e582950fcec88..e031cf594496b99d68c58dc44088f177ec32c091 100644 --- a/dbrepo-metadata-db/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptDto.java +++ b/dbrepo-metadata-db/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptDto.java @@ -1,5 +1,7 @@ package at.tuwien.api.database.table.columns.concepts; +import at.tuwien.api.database.table.columns.ColumnBriefDto; +import at.tuwien.api.database.table.columns.ColumnDto; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; @@ -9,6 +11,7 @@ import jakarta.validation.constraints.NotNull; import lombok.extern.jackson.Jacksonized; import java.time.Instant; +import java.util.List; @Getter @Setter @@ -26,7 +29,9 @@ public class ConceptDto { private String name; @NotNull - @Schema(required = true) @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC") private Instant created; + + @NotNull + private List<ColumnBriefDto> columns; } diff --git a/dbrepo-metadata-db/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitDto.java b/dbrepo-metadata-db/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitDto.java index a5429ceb9b56c9a0f687020a7f6809faf9252704..65b6c2a0bdcdbeb10c47975c1a43e9523259f773 100644 --- a/dbrepo-metadata-db/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitDto.java +++ b/dbrepo-metadata-db/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitDto.java @@ -1,7 +1,7 @@ package at.tuwien.api.database.table.columns.concepts; +import at.tuwien.api.database.table.columns.ColumnBriefDto; import com.fasterxml.jackson.annotation.JsonFormat; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import jakarta.validation.constraints.NotBlank; @@ -9,6 +9,7 @@ import jakarta.validation.constraints.NotNull; import lombok.extern.jackson.Jacksonized; import java.time.Instant; +import java.util.List; @Getter @Setter @@ -26,7 +27,9 @@ public class UnitDto { private String name; @NotNull - @Schema(required = true) @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC") private Instant created; + + @NotNull + private List<ColumnBriefDto> columns; } diff --git a/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnConcept.java b/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnConcept.java index 78e37ced97555cb71d2ff90efb62fd73791a64ed..fa2ae5a0666c3d289fadae19996f968b194b3ae0 100644 --- a/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnConcept.java +++ b/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnConcept.java @@ -36,4 +36,15 @@ public class TableColumnConcept { @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP") @CreatedDate private Instant created; + + @ToString.Exclude + @OneToMany(fetch = FetchType.LAZY) + @JoinTable(name = "mdb_columns_concepts", + inverseJoinColumns = { + @JoinColumn(name = "cid", referencedColumnName = "id", insertable = false, updatable = false), + @JoinColumn(name = "tid", referencedColumnName = "tid", insertable = false, updatable = false), + @JoinColumn(name = "cdbid", referencedColumnName = "cdbid", insertable = false, updatable = false) + }, + joinColumns = @JoinColumn(name = "uri", referencedColumnName = "uri")) + private List<TableColumn> columns; } diff --git a/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnUnit.java b/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnUnit.java index 1b93dea177774c038f734176e3402d12a7b0e192..aecbcd9dd354fc8d49b47a8021322dcadedf3598 100644 --- a/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnUnit.java +++ b/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnUnit.java @@ -36,4 +36,15 @@ public class TableColumnUnit { @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP") @CreatedDate private Instant created; + + @ToString.Exclude + @OneToMany(fetch = FetchType.LAZY) + @JoinTable(name = "mdb_columns_concepts", + inverseJoinColumns = { + @JoinColumn(name = "cid", referencedColumnName = "id", insertable = false, updatable = false), + @JoinColumn(name = "tid", referencedColumnName = "tid", insertable = false, updatable = false), + @JoinColumn(name = "cdbid", referencedColumnName = "cdbid", insertable = false, updatable = false) + }, + joinColumns = @JoinColumn(name = "uri", referencedColumnName = "uri")) + private List<TableColumn> columns; } diff --git a/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/semantics/Ontology.java b/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/semantics/Ontology.java index bb25ecd58a46a0ef1afacdd032c019fd566ac043..df63a7acf52ca59e6b80dbaeab10af5c8ce0135e 100644 --- a/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/semantics/Ontology.java +++ b/dbrepo-metadata-db/entities/src/main/java/at/tuwien/entities/semantics/Ontology.java @@ -29,10 +29,10 @@ public class Ontology { @Column(updatable = false, nullable = false) private Long id; - @Column(nullable = false) + @Column(nullable = false, unique = true) private String uri; - @Column(nullable = false, columnDefinition = "VARCHAR(8)") + @Column(nullable = false, unique = true, columnDefinition = "VARCHAR(8)") private String prefix; @Column diff --git a/dbrepo-metadata-db/setup-schema.sql b/dbrepo-metadata-db/setup-schema.sql index f57b6aad248b749c6aec92ca5aa740dd2d39c13f..9642c98f6152a0e691dffdbc4fd1332badced085 100644 --- a/dbrepo-metadata-db/setup-schema.sql +++ b/dbrepo-metadata-db/setup-schema.sql @@ -353,6 +353,8 @@ CREATE TABLE IF NOT EXISTS `fda`.`mdb_ontologies` last_modified timestamp, created timestamp NOT NULL DEFAULT NOW(), created_by character varying(255) NULL, + UNIQUE (prefix), + UNIQUE (uri), PRIMARY KEY (id) ) WITH SYSTEM VERSIONING; diff --git a/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/SemanticsEndpoint.java b/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/SemanticsEndpoint.java index 0e942b22e5ba264488ca3edf1a355ee9fb50ed96..6567d5ee38424c65946292583f8ef0002ef0e993 100644 --- a/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/SemanticsEndpoint.java +++ b/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/SemanticsEndpoint.java @@ -5,6 +5,7 @@ import at.tuwien.api.database.table.columns.concepts.ConceptSaveDto; import at.tuwien.api.database.table.columns.concepts.UnitDto; import at.tuwien.api.database.table.columns.concepts.UnitSaveDto; import at.tuwien.mapper.OntologyMapper; +import at.tuwien.mapper.SemanticMapper; import at.tuwien.service.SemanticService; import io.micrometer.core.annotation.Timed; import io.swagger.v3.oas.annotations.Operation; @@ -12,33 +13,62 @@ import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; +import java.util.List; + @Log4j2 @CrossOrigin(origins = "*") @RestController @RequestMapping("/api/semantic") public class SemanticsEndpoint { + private final SemanticMapper semanticMapper; private final OntologyMapper ontologyMapper; private final SemanticService semanticService; @Autowired - public SemanticsEndpoint(OntologyMapper ontologyMapper, SemanticService semanticService) { + public SemanticsEndpoint(SemanticMapper semanticMapper, OntologyMapper ontologyMapper, SemanticService semanticService) { + this.semanticMapper = semanticMapper; this.ontologyMapper = ontologyMapper; this.semanticService = semanticService; } + @GetMapping("/concept") + @Transactional(readOnly = true) + @Timed(value = "semantics.concept.list", description = "Time needed to find all semantic concepts") + @Operation(summary = "List semantic concepts") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Find all semantic concepts", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ConceptDto[].class))}), + }) + public ResponseEntity<List<ConceptDto>> findAllConcepts() { + log.debug("endpoint list concepts"); + final List<ConceptDto> dtos = semanticService.findAllConcepts() + .stream() + .map(semanticMapper::tableColumnConceptToConceptDto) + .toList(); + log.trace("Find all concepts resulted in dtos {}", dtos); + return ResponseEntity.ok() + .body(dtos); + } + @PostMapping("/concept") + @Transactional @PreAuthorize("hasAuthority('create-semantic-concept')") @Timed(value = "semantics.concept.save", description = "Time needed to create or update a semantic concept") - @Operation(summary = "Create or update a semantic concept") + @Operation(summary = "Create or update a semantic concept", security = @SecurityRequirement(name = "bearerAuth")) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Created or updated a semantic concept", @@ -50,14 +80,57 @@ public class SemanticsEndpoint { log.debug("endpoint save or update concept, data={}", data); final ConceptDto dto = ontologyMapper.tableColumnConceptToConceptDto(semanticService.saveConcept(data)); log.trace("save or update concept resulted in dto {}", dto); - return ResponseEntity.accepted() + return ResponseEntity.ok() + .body(dto); + } + + @PutMapping("/concept") + @Transactional + @PreAuthorize("hasAuthority('create-semantic-concept')") + @Timed(value = "semantics.concept.save", description = "Time needed to create or update a semantic concept") + @Operation(summary = "Create or update a semantic concept", security = @SecurityRequirement(name = "bearerAuth")) + @ApiResponses(value = { + @ApiResponse(responseCode = "202", + description = "Created or updated a semantic concept", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ConceptDto.class))}), + }) + public ResponseEntity<ConceptDto> saveConcept(@NotNull @Valid @RequestBody ConceptSaveDto data) { + log.debug("endpoint save or update concept, data={}", data); + final ConceptDto dto = ontologyMapper.tableColumnConceptToConceptDto(semanticService.saveConcept(data)); + log.trace("save or update concept resulted in dto {}", dto); + return ResponseEntity.ok() .body(dto); } + @GetMapping("/unit") + @Transactional(readOnly = true) + @Timed(value = "semantics.concept.list", description = "Time needed to find all semantic units") + @Operation(summary = "List semantic units") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Find all semantic units", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = UnitDto[].class))}), + }) + public ResponseEntity<List<UnitDto>> findAllUnits() { + log.debug("endpoint list units"); + final List<UnitDto> dtos = semanticService.findAllUnits() + .stream() + .map(semanticMapper::tableColumnUnitToUnitDto) + .toList(); + log.trace("Find all units resulted in dtos {}", dtos); + return ResponseEntity.ok() + .body(dtos); + } + @PostMapping("/unit") + @Transactional @PreAuthorize("hasAuthority('create-semantic-unit')") @Timed(value = "semantics.unit.save", description = "Time needed to create or update a semantic unit") - @Operation(summary = "Create or update a semantic unit") + @Operation(summary = "Create or update a semantic unit", security = @SecurityRequirement(name = "bearerAuth")) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Created or updated a semantic unit", diff --git a/dbrepo-semantics-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java b/dbrepo-semantics-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java index 3bd2ce6956ac3c52b301dbeacad582b6f68f9022..8b4729dcf0ff8a056f66a1881fff2e66813a2176 100644 --- a/dbrepo-semantics-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java +++ b/dbrepo-semantics-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java @@ -45,7 +45,9 @@ public class WebSecurityConfig { new AntPathRequestMatcher("/swagger-ui.html") ); final OrRequestMatcher publicEndpoints = new OrRequestMatcher( - new AntPathRequestMatcher("/api/semantic/ontology/**", "GET") + new AntPathRequestMatcher("/api/semantic/ontology/**", "GET"), + new AntPathRequestMatcher("/api/semantic/concept", "GET"), + new AntPathRequestMatcher("/api/semantic/unit", "GET") ); /* enable CORS and disable CSRF */ http = http.cors().and().csrf().disable(); diff --git a/dbrepo-semantics-service/services/src/main/java/at/tuwien/mapper/SemanticMapper.java b/dbrepo-semantics-service/services/src/main/java/at/tuwien/mapper/SemanticMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..95c56e0a5c53be6d910b33a637de29ec43da5a32 --- /dev/null +++ b/dbrepo-semantics-service/services/src/main/java/at/tuwien/mapper/SemanticMapper.java @@ -0,0 +1,18 @@ +package at.tuwien.mapper; + +import at.tuwien.api.database.table.columns.concepts.ConceptDto; +import at.tuwien.api.database.table.columns.concepts.UnitDto; +import at.tuwien.entities.database.table.columns.TableColumnConcept; +import at.tuwien.entities.database.table.columns.TableColumnUnit; +import org.mapstruct.Mapper; + + +@Mapper(componentModel = "spring", uses = {TableMapper.class}) +public interface SemanticMapper { + + org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SemanticMapper.class); + + ConceptDto tableColumnConceptToConceptDto(TableColumnConcept data); + + UnitDto tableColumnUnitToUnitDto(TableColumnUnit data); +} diff --git a/dbrepo-semantics-service/services/src/main/java/at/tuwien/mapper/TableMapper.java b/dbrepo-semantics-service/services/src/main/java/at/tuwien/mapper/TableMapper.java index 4f79866fcb749bd31c828d182dcd7b7235eb64f3..e5ae2d291b1fb12b437509a38c456af736a042fc 100644 --- a/dbrepo-semantics-service/services/src/main/java/at/tuwien/mapper/TableMapper.java +++ b/dbrepo-semantics-service/services/src/main/java/at/tuwien/mapper/TableMapper.java @@ -1,7 +1,12 @@ package at.tuwien.mapper; +import at.tuwien.api.database.table.columns.ColumnBriefDto; +import at.tuwien.api.database.table.columns.ColumnDto; +import at.tuwien.entities.database.table.columns.TableColumn; import at.tuwien.entities.database.table.columns.TableColumnKey; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; @Mapper(componentModel = "spring") @@ -9,6 +14,18 @@ public interface TableMapper { org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TableMapper.class); + @Mappings({ + @Mapping(source = "tid", target = "tableId"), + @Mapping(source = "cdbid", target = "databaseId"), + }) + ColumnBriefDto tableColumnToColumnBriefDto(TableColumn data); + + @Mappings({ + @Mapping(source = "tid", target = "tableId"), + @Mapping(source = "cdbid", target = "databaseId"), + }) + ColumnDto tableColumnToColumnDto(TableColumn data); + default TableColumnKey toTableColumnKey(Long databaseId, Long tableId, Long columnId) { return TableColumnKey.builder() .cdbid(databaseId) diff --git a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/SemanticService.java b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/SemanticService.java index 34fd117fcbe9e23370b4e14cf75c055cc97182e8..564b739af08341c7c1684e343ab36898bed354b7 100644 --- a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/SemanticService.java +++ b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/SemanticService.java @@ -5,7 +5,13 @@ import at.tuwien.api.database.table.columns.concepts.UnitSaveDto; import at.tuwien.entities.database.table.columns.TableColumnConcept; import at.tuwien.entities.database.table.columns.TableColumnUnit; +import java.util.List; + public interface SemanticService { + List<TableColumnConcept> findAllConcepts(); + + List<TableColumnUnit> findAllUnits(); + TableColumnConcept saveConcept(ConceptSaveDto data); TableColumnUnit saveUnit(UnitSaveDto data); diff --git a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/SemanticServiceImpl.java b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/SemanticServiceImpl.java index 66d9f751315b34f3ba2ef5343ba23b8451af391b..8c8cab046939d9c9a90a5b24b7dde8b1748ea537 100644 --- a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/SemanticServiceImpl.java +++ b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/SemanticServiceImpl.java @@ -11,6 +11,9 @@ import at.tuwien.service.SemanticService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; @Log4j2 @Service @@ -29,6 +32,21 @@ public class SemanticServiceImpl implements SemanticService { } @Override + @Transactional(readOnly = true) + public List<TableColumnConcept> findAllConcepts() { + final List<TableColumnConcept> concepts = tableColumnConceptRepository.findAll(); + return concepts; + } + + @Override + @Transactional(readOnly = true) + public List<TableColumnUnit> findAllUnits() { + final List<TableColumnUnit> units = tableColumnUnitRepository.findAll(); + return units; + } + + @Override + @Transactional public TableColumnConcept saveConcept(ConceptSaveDto data) { final TableColumnConcept entity = ontologyMapper.conceptSaveDtoToTableColumnConcept(data); final TableColumnConcept concept = tableColumnConceptRepository.save(entity); @@ -37,6 +55,7 @@ public class SemanticServiceImpl implements SemanticService { } @Override + @Transactional public TableColumnUnit saveUnit(UnitSaveDto data) { final TableColumnUnit entity = ontologyMapper.unitSaveDtoToTableColumnUnit(data); final TableColumnUnit unit = tableColumnUnitRepository.save(entity); diff --git a/dbrepo-ui/api/semantic.service.js b/dbrepo-ui/api/semantic.service.js index 750dbd2082e175ba72ddf53d7e6aff723daca7a9..0c9f01b7db6973e64ebe4f7c65f170deea8c7bb8 100644 --- a/dbrepo-ui/api/semantic.service.js +++ b/dbrepo-ui/api/semantic.service.js @@ -19,6 +19,40 @@ class SemanticService { }) } + findAllConcepts () { + return new Promise((resolve, reject) => { + api.get('/api/semantic/concept', { headers: { Accept: 'application/json' } }) + .then((response) => { + const concepts = response.data + console.debug('response concepts', concepts) + resolve(concepts) + }) + .catch((error) => { + const { code, message } = error + console.error('Failed to load concepts', error) + Vue.$toast.error(`[${code}] Failed to load concepts: ${message}`) + reject(error) + }) + }) + } + + findAllUnits () { + return new Promise((resolve, reject) => { + api.get('/api/semantic/unit', { headers: { Accept: 'application/json' } }) + .then((response) => { + const units = response.data + console.debug('response units', units) + resolve(units) + }) + .catch((error) => { + const { code, message } = error + console.error('Failed to load units', error) + Vue.$toast.error(`[${code}] Failed to load units: ${message}`) + reject(error) + }) + }) + } + findOntology (id) { return new Promise((resolve, reject) => { api.get(`/api/semantic/ontology/${id}`, { headers: { Accept: 'application/json' } }) diff --git a/dbrepo-ui/components/dialogs/EditSemantics.vue b/dbrepo-ui/components/dialogs/EditSemantics.vue new file mode 100644 index 0000000000000000000000000000000000000000..5debbc5840e681825688d2de715b9a0f7e943cb1 --- /dev/null +++ b/dbrepo-ui/components/dialogs/EditSemantics.vue @@ -0,0 +1,96 @@ +<template> + <div> + <v-card> + <v-card-title>Edit</v-card-title> + <v-card-text> + <v-form ref="form" v-model="valid" autocomplete="off" @submit.prevent="submit"> + <v-row> + <v-col> + <v-text-field + v-model="semanticDto.name" + clearable + label="Name" /> + </v-col> + </v-row> + <v-row> + <v-col> + <v-text-field + v-model="semanticDto.uri" + clearable + label="URI" + :rules="[v => !!v || $t('Required')]" + required /> + </v-col> + </v-row> + </v-form> + </v-card-text> + <v-card-actions> + <v-spacer /> + <v-btn + class="mb-2" + @click="cancel"> + Cancel + </v-btn> + <v-btn + color="primary" + class="mb-2 mr-2" + :disabled="!valid" + :loading="loadingSave" + @click="save"> + Save + </v-btn> + </v-card-actions> + </v-card> + </div> +</template> + +<script> +import SemanticService from '@/api/semantic.service' + +export default { + props: { + entity: { + type: Object, + default () { + return {} + } + } + }, + data () { + return { + valid: false, + localEntity: null, + loadingSave: false, + semanticDto: { + name: null, + uri: null + } + } + }, + computed: { + }, + watch: { + entity () { + this.semanticDto.name = this.entity.name + this.semanticDto.uri = this.entity.uri + } + }, + mounted () { + this.semanticDto.name = this.entity.name + this.semanticDto.uri = this.entity.uri + }, + methods: { + cancel () { + this.$emit('close', { success: false, action: 'cancel' }) + }, + save () { + SemanticService.u + }, + submit () { + this.$refs.form.validate() + } + } +} +</script> +<style scoped> +</style> diff --git a/dbrepo-ui/pages/semantic/index.vue b/dbrepo-ui/pages/semantic/index.vue index 6b924a606374f525e816b79c4ba71aaf92b37ddb..a9362fb6d3fd8dc25184604e3da5934f6d9dd117 100644 --- a/dbrepo-ui/pages/semantic/index.vue +++ b/dbrepo-ui/pages/semantic/index.vue @@ -5,19 +5,76 @@ <v-spacer /> <v-toolbar-title> <v-btn v-if="canListOntologies" to="/semantic/ontology" color="secondary"> - Ontologies + {{ ontologies.length }} Ontologies </v-btn> </v-toolbar-title> </v-toolbar> + <v-tabs v-model="tab"> + <v-tab>Concepts</v-tab> + <v-tab>Units</v-tab> + </v-tabs> + <v-card flat> + <v-card-text> + <v-data-table + :headers="headers" + :items="rows" + :options.sync="options" + :server-items-length="total" + :footer-props="footerProps"> + <template v-slot:item.uri="{ item }"> + <a :href="item.uri" target="_blank" v-text="item.uri" /> + </template> + <template v-slot:item.action="{ item }"> + <v-btn small @click="edit(item)"> + Edit + </v-btn> + </template> + </v-data-table> + </v-card-text> + </v-card> + <v-dialog + v-model="editSemanticDialog" + persistent + max-width="640"> + <EditSemantics :entity="entity" @close="close" /> + </v-dialog> <v-breadcrumbs :items="items" class="pa-0 mt-2" /> </div> </template> <script> +import SemanticService from '@/api/semantic.service' +import EditSemantics from '@/components/dialogs/EditSemantics.vue' + export default { components: { + EditSemantics }, data () { return { + loadingConcepts: false, + loadingUnits: false, + entity: null, + editSemanticDialog: false, + headers: [ + { text: 'Name', value: 'name' }, + { text: 'URI', value: 'uri' }, + { text: 'Usages', value: 'usages' }, + { text: null, value: 'action' } + ], + options: { + page: 1, + itemsPerPage: 10 + }, + total: -1, + footerProps: { + 'items-per-page-options': [10, 20, 30, 40, 50] + }, + tab: 0, + tabs: [ + 'concepts', 'units' + ], + concepts: [], + units: [], createOntologyDialog: false, items: [ { text: `${this.$t('layout.semantics', { name: 'vue-i18n' })}`, to: '/semantic', activeClass: '' } @@ -34,6 +91,12 @@ export default { roles () { return this.$store.state.roles }, + ontologies () { + return this.$store.state.ontologies + }, + rows () { + return this.tab === 0 ? this.concepts : this.units + }, canListOntologies () { if (!this.roles) { return false @@ -41,7 +104,46 @@ export default { return this.roles.includes('list-ontologies') } }, + mounted () { + this.loadUnits() + this.loadConcepts() + }, methods: { + loadConcepts () { + this.loadingConcepts = true + SemanticService.findAllConcepts() + .then((concepts) => { + concepts = concepts.map((column) => { + column.usages = column.columns.length + return column + }) + this.concepts = concepts + }) + .finally(() => { + this.loadingConcepts = false + }) + }, + loadUnits () { + this.loadingUnits = true + SemanticService.findAllUnits() + .then((units) => { + units = units.map((unit) => { + unit.usages = unit.columns.length + return unit + }) + this.units = units + }) + .finally(() => { + this.loadingUnits = false + }) + }, + edit (entity) { + this.entity = entity + this.editSemanticDialog = true + }, + close (event) { + this.editSemanticDialog = false + } } } </script> diff --git a/dbrepo-ui/pages/semantic/ontology/index.vue b/dbrepo-ui/pages/semantic/ontology/index.vue index f49d55364ac8645026e4329389dfb23aee806fbb..dcb79ccc929815d55a6e30ea4f1b21b4c46d5ab6 100644 --- a/dbrepo-ui/pages/semantic/ontology/index.vue +++ b/dbrepo-ui/pages/semantic/ontology/index.vue @@ -1,7 +1,7 @@ <template> <div v-if="canListOntologies"> <v-toolbar flat> - <v-toolbar-title>{{ $t('layout.ontologies', { name: 'vue-i18n' }) }}</v-toolbar-title> + <v-toolbar-title>{{ ontologies.length }} {{ $t('layout.ontologies', { name: 'vue-i18n' }) }}</v-toolbar-title> <v-spacer /> <v-toolbar-title> <v-btn v-if="canCreateOntology" color="primary" name="create-ontology" @click.stop="createOntologyDialog = true"> @@ -47,6 +47,9 @@ export default { roles () { return this.$store.state.roles }, + ontologies () { + return this.$store.state.ontologies + }, canListOntologies () { if (!this.roles) { return false