From 19e92f3ee0455550b75b0cc66b784ca7af88e805 Mon Sep 17 00:00:00 2001 From: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com> Date: Fri, 7 Jun 2024 21:20:50 +0200 Subject: [PATCH] Use RTK Query to obtain task/job information (#43798) * Type `TaskInfo` * Re-write `JobInfoApp` to use RTK Query * Re-write `JobTriggersModal` to use RTK Query * Remove unused `fetchJobInfo` action * Remove `TaskApi` from `services.js` * Remove `JobApp` styled component * Simplify fetching logic --- frontend/src/metabase-types/api/task.ts | 32 +++++++++ frontend/src/metabase/admin/routes.jsx | 4 +- .../admin/tasks/containers/JobInfoApp.jsx | 70 ++++++------------- .../tasks/containers/JobInfoApp.styled.tsx | 15 ---- .../tasks/containers/JobTriggersModal.jsx | 58 +++++---------- frontend/src/metabase/admin/tasks/jobInfo.js | 11 --- frontend/src/metabase/api/task.ts | 3 +- frontend/src/metabase/services.js | 4 -- 8 files changed, 77 insertions(+), 120 deletions(-) delete mode 100644 frontend/src/metabase/admin/tasks/containers/JobInfoApp.styled.tsx delete mode 100644 frontend/src/metabase/admin/tasks/jobInfo.js diff --git a/frontend/src/metabase-types/api/task.ts b/frontend/src/metabase-types/api/task.ts index 9efa69710b7..eea2c6ae1fa 100644 --- a/frontend/src/metabase-types/api/task.ts +++ b/frontend/src/metabase-types/api/task.ts @@ -15,3 +15,35 @@ export interface Task { export type ListTasksRequest = PaginationRequest; export type ListTasksResponse = { data: Task[] } & PaginationResponse; + +type Trigger = { + description: string | null; + schedule: string; + timezone: string; + key: string; + "previous-fire-time": string | null; + "start-time": string; + "misfire-instruction": string; + "end-time": string | null; + state: string; + priority: number; + "next-fire-time": string; + "may-fire-again?": boolean; + "final-fire-time": string | null; + data: Record<string, unknown>; +}; + +type Job = { + key: string; + class: string; + description: string; + "concurrent-execution-disallowed?": boolean; + "durable?": boolean; + "requests-recovery?": boolean; + triggers: Trigger[]; +}; + +export type TaskInfo = { + scheduler: string[]; + jobs: Job[]; +}; diff --git a/frontend/src/metabase/admin/routes.jsx b/frontend/src/metabase/admin/routes.jsx index 39ee91cb1f8..50f32fe8bd5 100644 --- a/frontend/src/metabase/admin/routes.jsx +++ b/frontend/src/metabase/admin/routes.jsx @@ -26,8 +26,8 @@ import getAdminPermissionsRoutes from "metabase/admin/permissions/routes"; import { SettingsEditor } from "metabase/admin/settings/app/components/SettingsEditor"; import { Help } from "metabase/admin/tasks/components/Help"; import { Logs } from "metabase/admin/tasks/components/Logs"; -import JobInfoApp from "metabase/admin/tasks/containers/JobInfoApp"; -import JobTriggersModal from "metabase/admin/tasks/containers/JobTriggersModal"; +import { JobInfoApp } from "metabase/admin/tasks/containers/JobInfoApp"; +import { JobTriggersModal } from "metabase/admin/tasks/containers/JobTriggersModal"; import { ModelCacheRefreshJobs, ModelCacheRefreshJobModal, diff --git a/frontend/src/metabase/admin/tasks/containers/JobInfoApp.jsx b/frontend/src/metabase/admin/tasks/containers/JobInfoApp.jsx index dff81f444b4..c8c9153951b 100644 --- a/frontend/src/metabase/admin/tasks/containers/JobInfoApp.jsx +++ b/frontend/src/metabase/admin/tasks/containers/JobInfoApp.jsx @@ -1,29 +1,21 @@ /* eslint-disable react/prop-types */ import cx from "classnames"; -import { Component } from "react"; -import { connect } from "react-redux"; import { t } from "ttag"; +import { useGetTasksInfoQuery } from "metabase/api"; import AdminHeader from "metabase/components/AdminHeader"; import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper"; import Link from "metabase/core/components/Link"; import AdminS from "metabase/css/admin.module.css"; import CS from "metabase/css/core/index.css"; - -import { fetchJobInfo } from "../jobInfo"; - -import { - JobInfoHeader, - JobInfoRoot, - JobSchedulerInfo, -} from "./JobInfoApp.styled"; +import { Box, Flex } from "metabase/ui"; const renderSchedulerInfo = scheduler => { return ( scheduler && ( - <JobSchedulerInfo> + <Flex align="center"> <pre>{scheduler.join("\n")}</pre> - </JobSchedulerInfo> + </Flex> ) ); }; @@ -64,40 +56,22 @@ const renderJobsTable = jobs => { ); }; -class JobInfoApp extends Component { - async componentDidMount() { - try { - const info = (await this.props.fetchJobInfo()).payload; - this.setState({ - scheduler: info.scheduler, - jobs: info.jobs, - error: null, - }); - } catch (error) { - this.setState({ error }); - } - } - - render() { - const { children } = this.props; - const { error, scheduler, jobs } = this.state || {}; - - return ( - <LoadingAndErrorWrapper loading={!scheduler} error={error}> - <JobInfoRoot> - <JobInfoHeader> - <AdminHeader title={t`Scheduler Info`} /> - </JobInfoHeader> - {renderSchedulerInfo(scheduler)} - {renderJobsTable(jobs)} - { - // render 'children' so that the invididual task modals show up - children - } - </JobInfoRoot> - </LoadingAndErrorWrapper> - ); - } -} +export const JobInfoApp = ({ children }) => { + const { data, error, isFetching } = useGetTasksInfoQuery(); -export default connect(null, { fetchJobInfo })(JobInfoApp); + return ( + <LoadingAndErrorWrapper loading={isFetching} error={error}> + <Box pl="md"> + <Flex align="center"> + <AdminHeader title={t`Scheduler Info`} /> + </Flex> + {renderSchedulerInfo(data?.scheduler)} + {renderJobsTable(data?.jobs)} + { + // render 'children' so that the invididual task modals show up + children + } + </Box> + </LoadingAndErrorWrapper> + ); +}; diff --git a/frontend/src/metabase/admin/tasks/containers/JobInfoApp.styled.tsx b/frontend/src/metabase/admin/tasks/containers/JobInfoApp.styled.tsx deleted file mode 100644 index 26558be7654..00000000000 --- a/frontend/src/metabase/admin/tasks/containers/JobInfoApp.styled.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import styled from "@emotion/styled"; - -export const JobInfoRoot = styled.div` - padding-left: 1rem; -`; - -export const JobInfoHeader = styled.div` - display: flex; - align-items: center; -`; - -export const JobSchedulerInfo = styled.div` - display: flex; - align-items: center; -`; diff --git a/frontend/src/metabase/admin/tasks/containers/JobTriggersModal.jsx b/frontend/src/metabase/admin/tasks/containers/JobTriggersModal.jsx index 53dea196578..a46137799db 100644 --- a/frontend/src/metabase/admin/tasks/containers/JobTriggersModal.jsx +++ b/frontend/src/metabase/admin/tasks/containers/JobTriggersModal.jsx @@ -1,17 +1,15 @@ /* eslint-disable react/prop-types */ import cx from "classnames"; -import { Component } from "react"; -import { connect } from "react-redux"; import { goBack } from "react-router-redux"; import { t } from "ttag"; import _ from "underscore"; +import { useGetTasksInfoQuery } from "metabase/api"; import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper"; import ModalContent from "metabase/components/ModalContent"; import AdminS from "metabase/css/admin.module.css"; import CS from "metabase/css/core/index.css"; - -import { fetchJobInfo } from "../jobInfo"; +import { useDispatch } from "metabase/lib/redux"; const renderTriggersTable = triggers => { return ( @@ -53,40 +51,22 @@ const renderTriggersTable = triggers => { ); }; -class JobTriggersModal extends Component { - state = { - triggers: null, - error: null, - }; - - async componentDidMount() { - try { - const { jobKey } = this.props.params; - const jobs = jobKey && (await this.props.fetchJobInfo()).payload.jobs; - const job = jobs && _.findWhere(jobs, { key: jobKey }); - const triggers = (job && job.triggers) || []; - - this.setState({ triggers, error: null }); - } catch (error) { - this.setState({ error }); - } - } - - render() { - const { - params: { jobKey }, - goBack, - } = this.props; - const { triggers, error } = this.state; +export const JobTriggersModal = props => { + const dispatch = useDispatch(); + const { data, error, isFetching } = useGetTasksInfoQuery(); - return ( - <ModalContent title={t`Triggers for ${jobKey}`} onClose={goBack}> - <LoadingAndErrorWrapper loading={!triggers} error={error}> - {() => renderTriggersTable(triggers)} - </LoadingAndErrorWrapper> - </ModalContent> - ); - } -} + const { jobKey } = props.params; + const jobs = jobKey && data?.jobs; + const job = jobs && _.findWhere(jobs, { key: jobKey }); -export default connect(null, { fetchJobInfo, goBack })(JobTriggersModal); + return ( + <ModalContent + title={t`Triggers for ${jobKey}`} + onClose={() => dispatch(goBack())} + > + <LoadingAndErrorWrapper loading={isFetching} error={error}> + {() => renderTriggersTable(job?.triggers)} + </LoadingAndErrorWrapper> + </ModalContent> + ); +}; diff --git a/frontend/src/metabase/admin/tasks/jobInfo.js b/frontend/src/metabase/admin/tasks/jobInfo.js deleted file mode 100644 index 3300110c3e8..00000000000 --- a/frontend/src/metabase/admin/tasks/jobInfo.js +++ /dev/null @@ -1,11 +0,0 @@ -import { createThunkAction } from "metabase/lib/redux"; -import { TaskApi } from "metabase/services"; - -export const FETCH_JOB_INFO = "metabase/admin/tasks/FETCH_JOB_INFO"; - -export const fetchJobInfo = createThunkAction( - FETCH_JOB_INFO, - () => async () => { - return await TaskApi.getJobsInfo(); - }, -); diff --git a/frontend/src/metabase/api/task.ts b/frontend/src/metabase/api/task.ts index 41e9bbb6184..32757b71e96 100644 --- a/frontend/src/metabase/api/task.ts +++ b/frontend/src/metabase/api/task.ts @@ -2,6 +2,7 @@ import type { ListTasksRequest, ListTasksResponse, Task, + TaskInfo, } from "metabase-types/api"; import { Api } from "./api"; @@ -25,7 +26,7 @@ export const taskApi = Api.injectEndpoints({ }), providesTags: task => (task ? provideTaskTags(task) : []), }), - getTasksInfo: builder.query<unknown, void>({ + getTasksInfo: builder.query<TaskInfo, void>({ query: () => ({ method: "GET", url: "/api/task/info", diff --git a/frontend/src/metabase/services.js b/frontend/src/metabase/services.js index 4f856a3f0ea..5231aecfc3e 100644 --- a/frontend/src/metabase/services.js +++ b/frontend/src/metabase/services.js @@ -457,10 +457,6 @@ export const I18NApi = { locale: GET("/app/locales/:locale.json"), }; -export const TaskApi = { - getJobsInfo: GET("/api/task/info"), -}; - export function setPublicQuestionEndpoints(uuid) { setCardEndpoints("/api/public/card/:uuid", { uuid }); } -- GitLab