From 53e094520dcc7e746efd4fec5c6a846b4c4c6455 Mon Sep 17 00:00:00 2001 From: Martin Weise <martin.weise@tuwien.ac.at> Date: Fri, 13 Dec 2024 14:41:52 +0100 Subject: [PATCH] Hotfix the UI --- .../java/at/tuwien/mapper/DataMapper.java | 16 ++- .../java/at/tuwien/mapper/MariaDbMapper.java | 2 +- .../impl/SubsetServiceMariaDbImpl.java | 2 - .../at/tuwien/endpoints/AccessEndpoint.java | 9 +- dbrepo-ui/components/subset/Results.vue | 47 ++++++- .../[database_id]/subset/[subset_id]/info.vue | 3 +- .../[database_id]/table/[table_id]/data.vue | 125 +++--------------- 7 files changed, 79 insertions(+), 125 deletions(-) diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java index ccb49288c5..3e569d2f12 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java @@ -21,7 +21,6 @@ import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto; import at.tuwien.api.database.table.constraints.unique.UniqueDto; import at.tuwien.api.user.UserDto; import at.tuwien.config.QueryConfig; -import at.tuwien.exception.QueryNotFoundException; import at.tuwien.exception.TableNotFoundException; import org.apache.hadoop.shaded.com.google.common.hash.Hashing; import org.apache.hadoop.shaded.org.apache.commons.io.FileUtils; @@ -199,17 +198,13 @@ public interface DataMapper { return view; } - default QueryDto resultSetToQueryDto(@NotNull ResultSet data) throws SQLException, QueryNotFoundException { + default QueryDto resultSetToQueryDto(@NotNull ResultSet data) throws SQLException { /* note that next() is called outside this mapping function */ - return QueryDto.builder() + final QueryDto subset = QueryDto.builder() .id(data.getLong(1)) .created(LocalDateTime.parse(data.getString(2), mariaDbFormatter) .atZone(ZoneId.of("UTC")) .toInstant()) - .creator(UserDto.builder() - .id(UUID.fromString(data.getString(3))) - .build()) - .createdBy(UUID.fromString(data.getString(3))) .query(data.getString(4)) .queryHash(data.getString(5)) .resultHash(data.getString(6)) @@ -219,6 +214,13 @@ public interface DataMapper { .atZone(ZoneId.of("UTC")) .toInstant()) .build(); + if (data.getString(3) != null) { + subset.setCreator(UserDto.builder() + .id(UUID.fromString(data.getString(3))) + .build()); + subset.setCreatedBy(UUID.fromString(data.getString(3))); + } + return subset; } default List<TableHistoryDto> resultSetToTableHistory(ResultSet resultSet) throws SQLException { diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java index 99480719fa..4e91dd7221 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java @@ -119,7 +119,7 @@ public interface MariaDbMapper { } default String queryStoreCreateTableRawQuery() { - final String statement = "CREATE TABLE `qs_queries` ( `id` bigint not null primary key default nextval(`qs_queries_seq`), `created` datetime not null default now(), `executed` datetime not null default now(), `created_by` varchar(36) not null, `query` text not null, `query_normalized` text not null, `is_persisted` boolean not null, `query_hash` varchar(255) not null, `result_hash` varchar(255), `result_number` bigint) WITH SYSTEM VERSIONING;"; + final String statement = "CREATE TABLE `qs_queries` ( `id` bigint not null primary key default nextval(`qs_queries_seq`), `created` datetime not null default now(), `executed` datetime not null default now(), `created_by` varchar(36), `query` text not null, `query_normalized` text not null, `is_persisted` boolean not null, `query_hash` varchar(255) not null, `result_hash` varchar(255), `result_number` bigint) WITH SYSTEM VERSIONING;"; log.trace("mapped create query store table statement: {}", statement); return statement; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java index 1e1e78603b..7e821af01c 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java @@ -180,8 +180,6 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs } final QueryDto query = dataMapper.resultSetToQueryDto(resultSet); query.setIdentifiers(metadataServiceGateway.getIdentifiers(database.getId(), queryId)); - query.setCreator(database.getOwner()); - query.setDatabaseId(database.getId()); return query; } catch (SQLException e) { log.error("Failed to find query with id {}: {}", queryId, e.getMessage()); diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java index 3b39857ee6..812ec7bc21 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java @@ -20,7 +20,6 @@ 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.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; @@ -92,7 +91,7 @@ public class AccessEndpoint { schema = @Schema(implementation = ApiErrorDto.class))}), }) public ResponseEntity<DatabaseAccessDto> create(@NotNull @PathVariable("databaseId") Long databaseId, - @org.hibernate.validator.constraints.UUID @PathVariable("userId") UUID userId, + @PathVariable("userId") UUID userId, @Valid @RequestBody UpdateDatabaseAccessDto data, @NotNull Principal principal) throws NotAllowedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, @@ -155,7 +154,7 @@ public class AccessEndpoint { schema = @Schema(implementation = ApiErrorDto.class))}), }) public ResponseEntity<Void> update(@NotNull @PathVariable("databaseId") Long databaseId, - @org.hibernate.validator.constraints.UUID @PathVariable("userId") UUID userId, + @PathVariable("userId") UUID userId, @Valid @RequestBody UpdateDatabaseAccessDto data, @NotNull Principal principal) throws NotAllowedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, @@ -200,7 +199,7 @@ public class AccessEndpoint { schema = @Schema(implementation = ApiErrorDto.class))}), }) public ResponseEntity<DatabaseAccessDto> find(@NotNull @PathVariable("databaseId") Long databaseId, - @org.hibernate.validator.constraints.UUID @PathVariable("userId") UUID userId, + @PathVariable("userId") UUID userId, @NotNull Principal principal) throws DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, NotAllowedException { log.debug("endpoint get database access, databaseId={}, userId={}, principal.name={}", databaseId, userId, @@ -257,7 +256,7 @@ public class AccessEndpoint { schema = @Schema(implementation = ApiErrorDto.class))}), }) public ResponseEntity<Void> revoke(@NotNull @PathVariable("databaseId") Long databaseId, - @org.hibernate.validator.constraints.UUID @PathVariable("userId") UUID userId, + @PathVariable("userId") UUID userId, @NotNull Principal principal) throws NotAllowedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, SearchServiceException, SearchServiceConnectionException { diff --git a/dbrepo-ui/components/subset/Results.vue b/dbrepo-ui/components/subset/Results.vue index ba063dcf5d..e9e3c0deb5 100644 --- a/dbrepo-ui/components/subset/Results.vue +++ b/dbrepo-ui/components/subset/Results.vue @@ -18,13 +18,15 @@ export default { props: { type: { type: String, - default: () => 'query' /* query or view */ + default: () => 'query' /* query, view or table */ }, loading: { type: Boolean, - default: () => { - return false - } + default: () => false + }, + timestamp: { + type: String, + default: () => new Date().toISOString() } }, data () { @@ -106,6 +108,25 @@ export default { .finally(() => { this.loadingExecute = false }) + } else if (this.type === 'table') { + const tableService = useTableService() + tableService.getData(this.$route.params.database_id, id, (this.options.page - 1), this.options.itemsPerPage, this.timestamp) + .then((result) => { + this.mapResults(result) + this.id = id + this.loadingExecute = false + }) + .catch(({code}) => { + this.loadingExecute = false + const toast = useToastInstance() + if (typeof code !== 'string') { + return + } + toast.error(this.$t(code)) + }) + .finally(() => { + this.loadingExecute = false + }) } else { const viewService = useViewService() viewService.reExecuteData(this.$route.params.database_id, id, this.options.page - 1, this.options.itemsPerPage) @@ -150,6 +171,24 @@ export default { .finally(() => { this.loadingCount = false }) + } else if (this.type === 'table') { + const tableService = useTableService() + tableService.getCount(this.$route.params.database_id, id, this.timestamp) + .then((count) => { + this.total = count + this.loadingCount = false + }) + .catch(({code}) => { + this.loadingCount = false + const toast = useToastInstance() + if (typeof code !== 'string') { + return + } + toast.error(this.$t(code)) + }) + .finally(() => { + this.loadingCount = false + }) } else { const viewService = useViewService() viewService.reExecuteCount(this.$route.params.database_id, id) diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue index b9ed74a042..764d1b55ff 100644 --- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue +++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue @@ -30,7 +30,7 @@ width="50%" /> </v-list> <v-list - v-else + v-else-if="subset" lines="two" dense> <v-list-item @@ -40,6 +40,7 @@ {{ database.is_public ? $t('toolbars.database.public') : $t('toolbars.database.private') }} </v-list-item> <v-list-item + v-if="subset.creator" :title="$t('pages.subset.creator.title')" density="compact"> <UserBadge :user="subset.creator" :other-user="user" /> diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue index 1be05e4bf1..1a29f918bf 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue @@ -55,36 +55,19 @@ </v-toolbar> <TimeDrift /> <v-card - elevation="0" - tile> - <v-card - v-if="error" - variant="flat"> - <v-card-text> - {{ $t('error.table.connection') }} - </v-card-text> - </v-card> - <v-data-table-server - v-if="!error" - v-model="selection" - flat - :show-select="canModify" - return-object - :headers="headers" - :items="rows" - :items-length="total" - :loading="loadingData || loadingCount" - :options.sync="options" - :footer-props="footerProps" - :items-per-page-options="footerProps.itemsPerPageOptions" - @update:options="loadData"> - <template - v-for="(blobColumn, idx) in blobColumns" - v-slot:[blobColumn]="{ item }"> - <BlobDownload - :blob="item[blobColumn.substring(5)]" /> - </template> - </v-data-table-server> + v-if="error" + variant="flat"> + <v-card-text> + {{ $t('error.table.connection') }} + </v-card-text> + </v-card> + <v-card tile> + <QueryResults + id="query-results" + ref="queryResults" + type="table" + :timestamp="versionISO || lastReload.toISOString()" + class="mt-0 mb-0" /> </v-card> <v-dialog v-model="pickVersionDialog" @@ -122,14 +105,16 @@ import TableHistory from '@/components/table/TableHistory.vue' import TimeDrift from '@/components/TimeDrift.vue' import TableToolbar from '@/components/table/TableToolbar.vue' -import {formatTimestampUTC, formatDateUTC, formatTimestamp} from '@/utils' +import { formatTimestamp } from '@/utils' import { useUserStore } from '@/stores/user' import { useCacheStore } from '@/stores/cache' import EditTuple from '@/components/dialogs/EditTuple.vue' import BlobDownload from '@/components/table/BlobDownload.vue' +import QueryResults from '@/components/subset/Results.vue' export default { components: { + QueryResults, BlobDownload, EditTuple, TableHistory, @@ -142,6 +127,7 @@ export default { loadingData: false, loadingCount: false, loadingDelete: false, + loadingTable: false, addTupleDialog: false, editTupleDialog: false, total: 0, @@ -282,18 +268,11 @@ export default { }, watch: { version () { - this.loadCount() this.reload() - }, - table (newTable, oldTable) { - if (newTable !== oldTable && oldTable === null) { - this.loadProperties() - } } }, mounted () { - this.loadProperties() - this.loadCount() + this.reload() }, methods: { addTuple () { @@ -402,74 +381,10 @@ export default { } this.pickVersionDialog = false }, - loadProperties () { - if (!this.table || this.headers.length > 0) { - return - } - try { - this.headers = [] - this.table.columns.map((c) => { - return { - value: c.internal_name, - title: c.internal_name, - sortable: false - } - }).forEach(header => this.headers.push(header)) - this.dateColumns = this.table.columns.filter(c => (c.column_type === 'date' || c.column_type === 'timestamp')) - console.debug('date columns are', this.dateColumns) - } catch ({code}) { - const toast = useToastInstance() - toast.error(this.$t(code)) - } - this.loading = false - }, reload () { this.lastReload = new Date() - this.loadData({ page: this.options.page, itemsPerPage: this.options.itemsPerPage, sortBy: null}) - }, - loadCount() { - this.loadingCount = true - const tableService = useTableService() - tableService.getCount(this.$route.params.database_id, this.$route.params.table_id, (this.versionISO || this.lastReload.toISOString())) - .then((count) => { - this.total = count - this.loadingCount = false - }) - .catch(({code}) => { - this.loadingCount = false - const toast = useToastInstance() - toast.error(this.$t(code)) - }) - }, - loadData({ page, itemsPerPage, sortBy }) { - this.options.page = page - this.options.itemsPerPage = itemsPerPage - const tableService = useTableService() - this.loadingData = true - tableService.getData(this.$route.params.database_id, this.$route.params.table_id, (page - 1), itemsPerPage, (this.versionISO || this.lastReload.toISOString())) - .then((data) => { - this.rows = data.result.map((row) => { - for (const col in row) { - const column = this.table.columns.filter(c => c.internal_name === col)[0] - const columnDefinition = this.dateColumns.filter(c => c.internal_name === col) - if (columnDefinition.length > 0) { - if (columnDefinition[0].column_type === 'date') { - row[col] = formatDateUTC(row[col]) - } else if (columnDefinition[0].column_type === 'timestamp') { - row[col] = formatTimestampUTC(row[col]) - } - } - } - return row - }) - this.loadingData = false - }) - .catch(({code, message}) => { - this.error = true - this.loadingData = false - const toast = useToastInstance() - toast.error(this.$t(code) + ": " + message) - }) + this.$refs.queryResults.reExecute(Number(this.$route.params.table_id)) + this.$refs.queryResults.reExecuteCount(Number(this.$route.params.table_id)) }, isFileField (column) { return ['blob', 'longblob', 'mediumblob', 'tinyblob'].includes(column.column_type) -- GitLab