Skip to content
Snippets Groups Projects
Unverified Commit 19e92f3e authored by Nemanja Glumac's avatar Nemanja Glumac Committed by GitHub
Browse files

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
parent bbde8ff5
No related branches found
No related tags found
No related merge requests found
......@@ -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[];
};
......@@ -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,
......
/* 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>
);
};
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;
`;
/* 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>
);
};
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();
},
);
......@@ -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",
......
......@@ -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 });
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment