From 48a644cdb718b7e7048fe516c78630d70e04c268 Mon Sep 17 00:00:00 2001 From: Jochen Klar Date: Thu, 11 Jul 2024 18:49:53 +0200 Subject: [PATCH] Add first browser component and refactor a bit --- daiquiri/core/assets/scss/base.scss | 1 + daiquiri/core/assets/scss/browser.scss | 48 +++++++++++ .../metadata/assets/js/api/MetadataApi.js | 11 +++ daiquiri/metadata/assets/js/hooks/queries.js | 10 +++ .../query/assets/js/query/components/App.js | 2 +- .../query/assets/js/query/components/Forms.js | 2 +- .../query/assets/js/query/components/Jobs.js | 2 +- .../assets/js/query/components/Status.js | 2 +- .../query/components/{form => forms}/Form.js | 2 +- .../components/{form => forms}/FormCustom.js | 5 +- .../components/{form => forms}/FormSql.js | 14 ++-- .../components/{form => forms}/FormUpload.js | 2 +- .../{form => forms}/common/Errors.js | 0 .../{form => forms}/common/Query.js | 0 .../{form => forms}/common/Select.js | 0 .../components/{form => forms}/common/Text.js | 0 .../forms/dropdowns/SchemaDropdown.js | 52 ++++++++++++ .../assets/js/query/components/job/Job.js | 2 +- .../js/query/components/job/JobAbortModal.js | 2 +- .../query/components/job/JobArchiveModal.js | 2 +- .../js/query/components/job/JobRenameModal.js | 2 +- .../js/query/components/job/JobResults.js | 2 +- .../query/assets/js/query/hooks/mutations.js | 82 +++++++++++++++++++ .../js/query/hooks/{query.js => queries.js} | 82 +------------------ 24 files changed, 223 insertions(+), 104 deletions(-) create mode 100644 daiquiri/core/assets/scss/browser.scss create mode 100644 daiquiri/metadata/assets/js/api/MetadataApi.js create mode 100644 daiquiri/metadata/assets/js/hooks/queries.js rename daiquiri/query/assets/js/query/components/{form => forms}/Form.js (93%) rename daiquiri/query/assets/js/query/components/{form => forms}/FormCustom.js (72%) rename daiquiri/query/assets/js/query/components/{form => forms}/FormSql.js (94%) rename daiquiri/query/assets/js/query/components/{form => forms}/FormUpload.js (99%) rename daiquiri/query/assets/js/query/components/{form => forms}/common/Errors.js (100%) rename daiquiri/query/assets/js/query/components/{form => forms}/common/Query.js (100%) rename daiquiri/query/assets/js/query/components/{form => forms}/common/Select.js (100%) rename daiquiri/query/assets/js/query/components/{form => forms}/common/Text.js (100%) create mode 100644 daiquiri/query/assets/js/query/components/forms/dropdowns/SchemaDropdown.js create mode 100644 daiquiri/query/assets/js/query/hooks/mutations.js rename daiquiri/query/assets/js/query/hooks/{query.js => queries.js} (50%) diff --git a/daiquiri/core/assets/scss/base.scss b/daiquiri/core/assets/scss/base.scss index bb16f85a..e5c069e4 100644 --- a/daiquiri/core/assets/scss/base.scss +++ b/daiquiri/core/assets/scss/base.scss @@ -6,6 +6,7 @@ $material-symbols-font-path: '~material-symbols/'; @import '~bootstrap/scss/bootstrap'; +@import 'browser'; @import 'card'; @import 'fonts'; @import 'footer'; diff --git a/daiquiri/core/assets/scss/browser.scss b/daiquiri/core/assets/scss/browser.scss new file mode 100644 index 00000000..d8d120dd --- /dev/null +++ b/daiquiri/core/assets/scss/browser.scss @@ -0,0 +1,48 @@ +.dq-browser { + .row { + div[class^='col'] { + border-right: var(--bs-card-border-width) solid var(--bs-card-border-color); + + &:last-child { + border-right: none; + } + } + + .dq-browser-title { + padding: 0.25rem 0.75rem; + border-bottom: var(--bs-card-border-width) solid var(--bs-card-border-color); + } + + .dq-browser-list { + margin: 0; + padding: 0; + + height: 100px; + overflow-y: auto; + + li { + margin: 0; + list-style: none; + + button.btn-link { + padding: 0.25rem 0.75rem; + border-radius: 0; + width: 100%; + text-align: left; + + text-decoration: none; + cursor: pointer; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + &:hover { + color: var(--dq-card-nav-hover-color); + background-color: var(--dq-card-nav-hover-bg); + } + } + } + } + } +} diff --git a/daiquiri/metadata/assets/js/api/MetadataApi.js b/daiquiri/metadata/assets/js/api/MetadataApi.js new file mode 100644 index 00000000..25d7d41c --- /dev/null +++ b/daiquiri/metadata/assets/js/api/MetadataApi.js @@ -0,0 +1,11 @@ +import BaseApi from 'daiquiri/core/assets/js/api/BaseApi' + +class MetadataApi extends BaseApi { + + static fetchUserSchemas() { + return this.get('/metadata/api/schemas/user/') + } + +} + +export default MetadataApi diff --git a/daiquiri/metadata/assets/js/hooks/queries.js b/daiquiri/metadata/assets/js/hooks/queries.js new file mode 100644 index 00000000..077a1d15 --- /dev/null +++ b/daiquiri/metadata/assets/js/hooks/queries.js @@ -0,0 +1,10 @@ +import { keepPreviousData, useQuery } from '@tanstack/react-query' +import MetadataApi from '../api/MetadataApi' + +export const useUserSchemasQuery = () => { + return useQuery({ + queryKey: ['schemasUser'], + queryFn: () => MetadataApi.fetchUserSchemas(), + placeholderData: keepPreviousData + }) +} diff --git a/daiquiri/query/assets/js/query/components/App.js b/daiquiri/query/assets/js/query/components/App.js index edbe0236..35a8c532 100644 --- a/daiquiri/query/assets/js/query/components/App.js +++ b/daiquiri/query/assets/js/query/components/App.js @@ -2,7 +2,7 @@ import React, { useState } from 'react' import { parseLocation, updateLocation } from '../utils/location' -import Form from './form/Form' +import Form from './forms/Form' import Forms from './Forms' import Job from './job/Job' import Jobs from './Jobs' diff --git a/daiquiri/query/assets/js/query/components/Forms.js b/daiquiri/query/assets/js/query/components/Forms.js index f20cae16..cdfa2791 100644 --- a/daiquiri/query/assets/js/query/components/Forms.js +++ b/daiquiri/query/assets/js/query/components/Forms.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types' import classNames from 'classnames' import { isNil } from 'lodash' -import { useFormsQuery } from '../hooks/query' +import { useFormsQuery } from '../hooks/queries' import { basePath } from '../utils/location' import Loading from './Loading' diff --git a/daiquiri/query/assets/js/query/components/Jobs.js b/daiquiri/query/assets/js/query/components/Jobs.js index 6282d72f..5d3d30c8 100644 --- a/daiquiri/query/assets/js/query/components/Jobs.js +++ b/daiquiri/query/assets/js/query/components/Jobs.js @@ -6,7 +6,7 @@ import { isEmpty, isNil } from 'lodash' import { baseUrl, userId } from 'daiquiri/core/assets/js/utils/meta' import { useLsState } from 'daiquiri/core/assets/js/hooks/ls' -import { useJobsQuery } from '../hooks/query' +import { useJobsQuery } from '../hooks/queries' import { basePath } from '../utils/location' import Loading from './Loading' diff --git a/daiquiri/query/assets/js/query/components/Status.js b/daiquiri/query/assets/js/query/components/Status.js index 214a16e1..f49f8d64 100644 --- a/daiquiri/query/assets/js/query/components/Status.js +++ b/daiquiri/query/assets/js/query/components/Status.js @@ -4,7 +4,7 @@ import { isNil } from 'lodash' import { baseUrl } from 'daiquiri/core/assets/js/utils/meta' import { bytes2human } from 'daiquiri/core/assets/js/utils/bytes' -import { useStatusQuery } from '../hooks/query' +import { useStatusQuery } from '../hooks/queries' const Status = () => { const { data: status } = useStatusQuery() diff --git a/daiquiri/query/assets/js/query/components/form/Form.js b/daiquiri/query/assets/js/query/components/forms/Form.js similarity index 93% rename from daiquiri/query/assets/js/query/components/form/Form.js rename to daiquiri/query/assets/js/query/components/forms/Form.js index 1b81e5fd..53209313 100644 --- a/daiquiri/query/assets/js/query/components/form/Form.js +++ b/daiquiri/query/assets/js/query/components/forms/Form.js @@ -2,7 +2,7 @@ import React from 'react' import PropTypes from 'prop-types' import { isNil } from 'lodash' -import { useFormQuery } from '../../hooks/query' +import { useFormQuery } from '../../hooks/queries' import FormSql from './FormSql' import FormCustom from './FormCustom' diff --git a/daiquiri/query/assets/js/query/components/form/FormCustom.js b/daiquiri/query/assets/js/query/components/forms/FormCustom.js similarity index 72% rename from daiquiri/query/assets/js/query/components/form/FormCustom.js rename to daiquiri/query/assets/js/query/components/forms/FormCustom.js index dbbb5008..0003f1d1 100644 --- a/daiquiri/query/assets/js/query/components/form/FormCustom.js +++ b/daiquiri/query/assets/js/query/components/forms/FormCustom.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types' import Template from 'daiquiri/core/assets/js/components/Template' -const FormCustom = ({ form, loadJob }) => { +const FormCustom = ({ form }) => { return (

{form.label}

@@ -13,8 +13,7 @@ const FormCustom = ({ form, loadJob }) => { } FormCustom.propTypes = { - form: PropTypes.object.isRequired, - loadJob: PropTypes.func.isRequired + form: PropTypes.object.isRequired } export default FormCustom diff --git a/daiquiri/query/assets/js/query/components/form/FormSql.js b/daiquiri/query/assets/js/query/components/forms/FormSql.js similarity index 94% rename from daiquiri/query/assets/js/query/components/form/FormSql.js rename to daiquiri/query/assets/js/query/components/forms/FormSql.js index 38cbe18f..40eaf2e7 100644 --- a/daiquiri/query/assets/js/query/components/form/FormSql.js +++ b/daiquiri/query/assets/js/query/components/forms/FormSql.js @@ -6,11 +6,14 @@ import { useLsState } from 'daiquiri/core/assets/js/hooks/ls' import Template from 'daiquiri/core/assets/js/components/Template' +import { useQueryLanguagesQuery, useQueuesQuery } from '../../hooks/queries' +import { useSubmitJobMutation } from '../../hooks/mutations' + import Query from './common/Query' import Select from './common/Select' import Text from './common/Text' -import { useQueryLanguagesQuery, useQueuesQuery, useSubmitJobMutation } from '../../hooks/query' +import SchemaDropdown from './dropdowns/SchemaDropdown' const FormSql = ({ form, loadJob, query }) => { @@ -23,7 +26,6 @@ const FormSql = ({ form, loadJob, query }) => { }) const [errors, setErrors] = useState({}) - const { data: queues } = useQueuesQuery() const { data: queryLanguages } = useQueryLanguagesQuery() const mutation = useSubmitJobMutation() @@ -90,13 +92,7 @@ const FormSql = ({ form, loadJob, query }) => {
{ - openDropdown && ( -
-
- {openDropdown} -
-
- ) + openDropdown == 'schemas' && } diff --git a/daiquiri/query/assets/js/query/components/form/FormUpload.js b/daiquiri/query/assets/js/query/components/forms/FormUpload.js similarity index 99% rename from daiquiri/query/assets/js/query/components/form/FormUpload.js rename to daiquiri/query/assets/js/query/components/forms/FormUpload.js index 1fb7e958..ba31e061 100644 --- a/daiquiri/query/assets/js/query/components/form/FormUpload.js +++ b/daiquiri/query/assets/js/query/components/forms/FormUpload.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types' import Template from 'daiquiri/core/assets/js/components/Template' import { bytes2human } from 'daiquiri/core/assets/js/utils/bytes' -import { useStatusQuery, useUploadJobMutation } from '../../hooks/query' +import { useStatusQuery, useUploadJobMutation } from '../../hooks/queries' import Text from './common/Text' diff --git a/daiquiri/query/assets/js/query/components/form/common/Errors.js b/daiquiri/query/assets/js/query/components/forms/common/Errors.js similarity index 100% rename from daiquiri/query/assets/js/query/components/form/common/Errors.js rename to daiquiri/query/assets/js/query/components/forms/common/Errors.js diff --git a/daiquiri/query/assets/js/query/components/form/common/Query.js b/daiquiri/query/assets/js/query/components/forms/common/Query.js similarity index 100% rename from daiquiri/query/assets/js/query/components/form/common/Query.js rename to daiquiri/query/assets/js/query/components/forms/common/Query.js diff --git a/daiquiri/query/assets/js/query/components/form/common/Select.js b/daiquiri/query/assets/js/query/components/forms/common/Select.js similarity index 100% rename from daiquiri/query/assets/js/query/components/form/common/Select.js rename to daiquiri/query/assets/js/query/components/forms/common/Select.js diff --git a/daiquiri/query/assets/js/query/components/form/common/Text.js b/daiquiri/query/assets/js/query/components/forms/common/Text.js similarity index 100% rename from daiquiri/query/assets/js/query/components/form/common/Text.js rename to daiquiri/query/assets/js/query/components/forms/common/Text.js diff --git a/daiquiri/query/assets/js/query/components/forms/dropdowns/SchemaDropdown.js b/daiquiri/query/assets/js/query/components/forms/dropdowns/SchemaDropdown.js new file mode 100644 index 00000000..62f685aa --- /dev/null +++ b/daiquiri/query/assets/js/query/components/forms/dropdowns/SchemaDropdown.js @@ -0,0 +1,52 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import { useUserSchemasQuery } from 'daiquiri/metadata/assets/js/hooks/queries' +import { useUserSchemaQuery } from '../../../hooks/queries' + +const SchemaDropdown = ({ }) => { + const { data: schemas } = useUserSchemasQuery() + const { data: userSchema } = useUserSchemaQuery() + + console.log(schemas) + console.log(userSchema) + + return ( +
+
+
+
+
+ {gettext('Schemas')} +
+
    +
  • +
+
+
+
+ {gettext('Tables')} +
+
    +
  • +
+
+
+
+ {gettext('Columns')} +
+
    +
  • +
+
+
+
+
+ ) +} + +SchemaDropdown.propTypes = { + +} + +export default SchemaDropdown diff --git a/daiquiri/query/assets/js/query/components/job/Job.js b/daiquiri/query/assets/js/query/components/job/Job.js index acea1d2d..61debb0a 100644 --- a/daiquiri/query/assets/js/query/components/job/Job.js +++ b/daiquiri/query/assets/js/query/components/job/Job.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types' import { isNil } from 'lodash' import classNames from 'classnames' -import { useJobQuery } from '../../hooks/query' +import { useJobQuery } from '../../hooks/queries' import { useLsState } from 'daiquiri/core/assets/js/hooks/ls' diff --git a/daiquiri/query/assets/js/query/components/job/JobAbortModal.js b/daiquiri/query/assets/js/query/components/job/JobAbortModal.js index bb41ef52..ce7cc0b1 100644 --- a/daiquiri/query/assets/js/query/components/job/JobAbortModal.js +++ b/daiquiri/query/assets/js/query/components/job/JobAbortModal.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types' import { useModal } from 'daiquiri/core/assets/js/hooks/modal' -import { useAbortJobMutation } from '../../hooks/query' +import { useAbortJobMutation } from '../../hooks/mutations' const JobAbortModal = ({ job, show, toggle }) => { const [ref, showModal, hideModal] = useModal() diff --git a/daiquiri/query/assets/js/query/components/job/JobArchiveModal.js b/daiquiri/query/assets/js/query/components/job/JobArchiveModal.js index cc8952d2..5373cdb2 100644 --- a/daiquiri/query/assets/js/query/components/job/JobArchiveModal.js +++ b/daiquiri/query/assets/js/query/components/job/JobArchiveModal.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types' import { useModal } from 'daiquiri/core/assets/js/hooks/modal' -import { useArchiveJobMutation } from '../../hooks/query' +import { useArchiveJobMutation } from '../../hooks/mutations' const JobArchiveModal = ({ job, show, toggle }) => { const [ref, showModal, hideModal] = useModal() diff --git a/daiquiri/query/assets/js/query/components/job/JobRenameModal.js b/daiquiri/query/assets/js/query/components/job/JobRenameModal.js index 69b0cdff..2117a34d 100644 --- a/daiquiri/query/assets/js/query/components/job/JobRenameModal.js +++ b/daiquiri/query/assets/js/query/components/job/JobRenameModal.js @@ -4,7 +4,7 @@ import className from 'classnames' import { useModal } from 'daiquiri/core/assets/js/hooks/modal' -import { useUpdateJobMutation } from '../../hooks/query' +import { useUpdateJobMutation } from '../../hooks/mutations' const JobRenameModal = ({ job, show, toggle }) => { const [ref, showModal, hideModal] = useModal() diff --git a/daiquiri/query/assets/js/query/components/job/JobResults.js b/daiquiri/query/assets/js/query/components/job/JobResults.js index 663a9b97..c426954d 100644 --- a/daiquiri/query/assets/js/query/components/job/JobResults.js +++ b/daiquiri/query/assets/js/query/components/job/JobResults.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types' import Table from 'daiquiri/core/assets/js/components/Table' -import { useJobColumnsQuery, useJobRowsQuery } from '../../hooks/query' +import { useJobColumnsQuery, useJobRowsQuery } from '../../hooks/queries' const JobResults = ({ job }) => { const [params, setParams] = useState({ diff --git a/daiquiri/query/assets/js/query/hooks/mutations.js b/daiquiri/query/assets/js/query/hooks/mutations.js new file mode 100644 index 00000000..d7480259 --- /dev/null +++ b/daiquiri/query/assets/js/query/hooks/mutations.js @@ -0,0 +1,82 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query' +import QueryApi from '../api/QueryApi' + +export const useSubmitJobMutation = () => { + const queryClient = useQueryClient() + + return useMutation({ + mutationFn: (variables) => { + return QueryApi.submitJob(variables.values) + }, + onSuccess: (data, variables) => { + variables.loadJob(data.id) + queryClient.invalidateQueries({ queryKey: ['jobs'] }) + }, + onError: (error, variables) => { + variables.setErrors(error.errors) + } + }) +} + +export const useUploadJobMutation = () => { + const queryClient = useQueryClient() + + return useMutation({ + mutationFn: (variables) => { + return QueryApi.uploadJob(variables.values) + }, + onSuccess: (data, variables) => { + variables.loadJob(data.id) + queryClient.invalidateQueries({ queryKey: ['jobs'] }) + }, + onError: (error, variables) => { + variables.setErrors(error.errors) + } + }) +} + +export const useUpdateJobMutation = () => { + const queryClient = useQueryClient() + + return useMutation({ + mutationFn: (variables) => { + return QueryApi.updateJob(variables.job.id, variables.values) + }, + onSuccess: (data, variables) => { + queryClient.setQueryData(['job', variables.job.id], {...variables.job, ...data}) + queryClient.invalidateQueries({ queryKey: ['jobs'] }) + variables.onSuccess() + }, + onError: (error, variables) => { + variables.setErrors(error.errors) + } + }) +} + +export const useArchiveJobMutation = () => { + const queryClient = useQueryClient() + + return useMutation({ + mutationFn: (variables) => { + return QueryApi.archiveJob(variables.job.id) + }, + onSuccess: (data, variables) => { + queryClient.invalidateQueries({ queryKey: ['jobs'] }) + variables.onSuccess() + } + }) +} + +export const useAbortJobMutation = () => { + const queryClient = useQueryClient() + + return useMutation({ + mutationFn: (variables) => { + return QueryApi.abortJob(variables.job.id) + }, + onSuccess: (data, variables) => { + queryClient.invalidateQueries({ queryKey: ['jobs'] }) + variables.onSuccess() + } + }) +} diff --git a/daiquiri/query/assets/js/query/hooks/query.js b/daiquiri/query/assets/js/query/hooks/queries.js similarity index 50% rename from daiquiri/query/assets/js/query/hooks/query.js rename to daiquiri/query/assets/js/query/hooks/queries.js index 071650c9..ca95f23a 100644 --- a/daiquiri/query/assets/js/query/hooks/query.js +++ b/daiquiri/query/assets/js/query/hooks/queries.js @@ -1,4 +1,4 @@ -import { keepPreviousData, useQuery, useMutation, useQueryClient } from '@tanstack/react-query' +import { keepPreviousData, useQuery } from '@tanstack/react-query' import QueryApi from '../api/QueryApi' const refetchInterval = 4000 @@ -85,83 +85,3 @@ export const useJobRowsQuery = (jobId, params) => { placeholderData: keepPreviousData }) } - -export const useSubmitJobMutation = () => { - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: (variables) => { - return QueryApi.submitJob(variables.values) - }, - onSuccess: (data, variables) => { - variables.loadJob(data.id) - queryClient.invalidateQueries({ queryKey: ['jobs'] }) - }, - onError: (error, variables) => { - variables.setErrors(error.errors) - } - }) -} - -export const useUploadJobMutation = () => { - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: (variables) => { - return QueryApi.uploadJob(variables.values) - }, - onSuccess: (data, variables) => { - variables.loadJob(data.id) - queryClient.invalidateQueries({ queryKey: ['jobs'] }) - }, - onError: (error, variables) => { - variables.setErrors(error.errors) - } - }) -} - -export const useUpdateJobMutation = () => { - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: (variables) => { - return QueryApi.updateJob(variables.job.id, variables.values) - }, - onSuccess: (data, variables) => { - queryClient.setQueryData(['job', variables.job.id], {...variables.job, ...data}) - queryClient.invalidateQueries({ queryKey: ['jobs'] }) - variables.onSuccess() - }, - onError: (error, variables) => { - variables.setErrors(error.errors) - } - }) -} - -export const useArchiveJobMutation = () => { - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: (variables) => { - return QueryApi.archiveJob(variables.job.id) - }, - onSuccess: (data, variables) => { - queryClient.invalidateQueries({ queryKey: ['jobs'] }) - variables.onSuccess() - } - }) -} - -export const useAbortJobMutation = () => { - const queryClient = useQueryClient() - - return useMutation({ - mutationFn: (variables) => { - return QueryApi.abortJob(variables.job.id) - }, - onSuccess: (data, variables) => { - queryClient.invalidateQueries({ queryKey: ['jobs'] }) - variables.onSuccess() - } - }) -}