Skip to content

Commit 8093543

Browse files
authored
Merge pull request #39 from skbkontur/gafetinov/upgrade-for-diadoc
Gafetinov/upgrade for diadoc
2 parents 099dfe1 + cf5bb31 commit 8093543

26 files changed

+505
-373
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## v3.1.0 - 2023.12.05
4+
- add multiple choice for tasks
5+
- add prop for custom status names
6+
- add prop for hiding null data in meta table
7+
- add prop for custom search help
8+
- small update of layout
9+
310
## v3.0.0 - 2023.10.23
411
- Add new bundler Vite instead of WebPack
512
- Update Node to v20

cassandra-distributed-task-queue-ui/.eslintrc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
"@typescript-eslint/explicit-member-accessibility": "error",
4646
"@typescript-eslint/explicit-function-return-type": "off",
4747
"react/no-deprecated": "warn",
48-
"react/prop-types": "off"
48+
"react/prop-types": "off",
49+
"react/display-name": "warn"
4950
},
5051
"ignorePatterns": ["dist/", "react-selenium-testing.js"],
5152
"settings": {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { createContext, PropsWithChildren, useContext } from "react";
2+
import type { JSX } from "react";
3+
4+
import { TaskState } from "./Domain/Api/TaskState";
5+
import { CustomRenderer, ICustomRenderer } from "./Domain/CustomRenderer";
6+
7+
const TaskStateCaptions = {
8+
[TaskState.Unknown]: "Unknown",
9+
[TaskState.New]: "New",
10+
[TaskState.WaitingForRerun]: "Waiting for rerun",
11+
[TaskState.WaitingForRerunAfterError]: "Waiting for rerun after error",
12+
[TaskState.Finished]: "Finished",
13+
[TaskState.InProcess]: "In process",
14+
[TaskState.Fatal]: "Fatal",
15+
[TaskState.Canceled]: "Canceled",
16+
};
17+
18+
export type TaskStateDict = Partial<Record<TaskState, string>>;
19+
20+
export interface ICustomSettings {
21+
customDetailRenderer: ICustomRenderer;
22+
customStateCaptions: TaskStateDict;
23+
hideMissingMeta: boolean;
24+
customSearchHelp?: JSX.Element;
25+
}
26+
27+
const defaultValue: ICustomSettings = {
28+
customStateCaptions: TaskStateCaptions,
29+
customDetailRenderer: new CustomRenderer(),
30+
hideMissingMeta: false,
31+
};
32+
33+
const CustomSettingsContext = createContext<ICustomSettings>(defaultValue);
34+
35+
export const CustomSettingsProvider = ({
36+
customStateCaptions,
37+
customSearchHelp,
38+
customDetailRenderer,
39+
hideMissingMeta,
40+
children,
41+
}: PropsWithChildren<Partial<ICustomSettings>>) => {
42+
const stateCaptions = customStateCaptions || TaskStateCaptions;
43+
const renderer = customDetailRenderer || new CustomRenderer();
44+
return (
45+
<CustomSettingsContext.Provider
46+
value={{
47+
customStateCaptions: stateCaptions,
48+
customDetailRenderer: renderer,
49+
customSearchHelp,
50+
hideMissingMeta: !!hideMissingMeta,
51+
}}>
52+
{children}
53+
</CustomSettingsContext.Provider>
54+
);
55+
};
56+
57+
export const useCustomSettings = () => useContext(CustomSettingsContext);

cassandra-distributed-task-queue-ui/src/Domain/QueryStringMapping/Mappers.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isValid, parse as parseDateInternal } from "date-fns";
1+
import { endOfDay, isValid, parse as parseDateInternal, startOfDay } from "date-fns";
22
import difference from "lodash/difference";
33

44
import { DateTimeRange } from "../DataTypes/DateTimeRange";
@@ -147,8 +147,8 @@ export class DateTimeRangeMapper {
147147
return this.defaultValue;
148148
}
149149
return {
150-
lowerBound: lowerBound,
151-
upperBound: upperBound,
150+
lowerBound: lowerBound && startOfDay(lowerBound),
151+
upperBound: upperBound && endOfDay(upperBound),
152152
};
153153
}
154154

cassandra-distributed-task-queue-ui/src/Domain/RtqMonitoringSearchRequestUtils.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export function createDefaultRemoteTaskQueueSearchRequest(): RtqMonitoringSearch
2121
}
2222

2323
export function isRemoteTaskQueueSearchRequestEmpty(searchRequest: Nullable<RtqMonitoringSearchRequest>): boolean {
24-
if (searchRequest === null || searchRequest === undefined) {
24+
if (!searchRequest) {
2525
return true;
2626
}
2727
return (
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import Decimal from "decimal.js";
22

3-
export function ticksToMilliseconds(timeStr: Nullable<string>): Nullable<number> {
3+
export function ticksToMilliseconds(timeStr: Nullable<string>): Nullable<string> {
44
if (!timeStr) {
55
return null;
66
}
77
const commonTime = new Decimal(timeStr);
8-
return commonTime.div(10000).toNumber();
8+
return commonTime.div(10000).toString();
99
}
Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import type { JSX } from "react";
12
import { Routes, Route } from "react-router-dom";
23

4+
import { CustomSettingsProvider, TaskStateDict } from "./CustomSettingsContext";
35
import { IRtqMonitoringApi } from "./Domain/Api/RtqMonitoringApi";
46
import { ICustomRenderer } from "./Domain/CustomRenderer";
57
import { TaskChainsTreeContainer } from "./containers/TaskChainsTreeContainer";
@@ -11,44 +13,55 @@ interface RemoteTaskQueueApplicationProps {
1113
customRenderer: ICustomRenderer;
1214
useErrorHandlingContainer: boolean;
1315
isSuperUser: boolean;
16+
customStateCaptions?: TaskStateDict;
17+
customSearchHelp?: JSX.Element;
18+
hideMissingMeta?: boolean;
1419
}
1520

1621
export const RemoteTaskQueueApplication = ({
1722
isSuperUser,
1823
rtqMonitoringApi,
19-
customRenderer,
2024
useErrorHandlingContainer,
25+
customRenderer,
26+
customStateCaptions,
27+
customSearchHelp,
28+
hideMissingMeta,
2129
}: RemoteTaskQueueApplicationProps): JSX.Element => (
22-
<Routes>
23-
<Route
24-
path="/"
25-
element={
26-
<TasksPageContainer
27-
isSuperUser={isSuperUser}
28-
rtqMonitoringApi={rtqMonitoringApi}
29-
useErrorHandlingContainer={useErrorHandlingContainer}
30-
/>
31-
}
32-
/>
33-
<Route
34-
path="Tree"
35-
element={
36-
<TaskChainsTreeContainer
37-
rtqMonitoringApi={rtqMonitoringApi}
38-
useErrorHandlingContainer={useErrorHandlingContainer}
39-
/>
40-
}
41-
/>
42-
<Route
43-
path=":id"
44-
element={
45-
<TaskDetailsPageContainer
46-
isSuperUser={isSuperUser}
47-
rtqMonitoringApi={rtqMonitoringApi}
48-
customRenderer={customRenderer}
49-
useErrorHandlingContainer={useErrorHandlingContainer}
50-
/>
51-
}
52-
/>
53-
</Routes>
30+
<CustomSettingsProvider
31+
customStateCaptions={customStateCaptions}
32+
customSearchHelp={customSearchHelp}
33+
customDetailRenderer={customRenderer}
34+
hideMissingMeta={hideMissingMeta}>
35+
<Routes>
36+
<Route
37+
path="/"
38+
element={
39+
<TasksPageContainer
40+
isSuperUser={isSuperUser}
41+
rtqMonitoringApi={rtqMonitoringApi}
42+
useErrorHandlingContainer={useErrorHandlingContainer}
43+
/>
44+
}
45+
/>
46+
<Route
47+
path="Tree"
48+
element={
49+
<TaskChainsTreeContainer
50+
rtqMonitoringApi={rtqMonitoringApi}
51+
useErrorHandlingContainer={useErrorHandlingContainer}
52+
/>
53+
}
54+
/>
55+
<Route
56+
path=":id"
57+
element={
58+
<TaskDetailsPageContainer
59+
isSuperUser={isSuperUser}
60+
rtqMonitoringApi={rtqMonitoringApi}
61+
useErrorHandlingContainer={useErrorHandlingContainer}
62+
/>
63+
}
64+
/>
65+
</Routes>
66+
</CustomSettingsProvider>
5467
);

cassandra-distributed-task-queue-ui/src/components/TaskDetailsMetaTable/TaskDetailsMetaTable.tsx

Lines changed: 27 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ThemeContext } from "@skbkontur/react-ui";
2-
import React from "react";
2+
import React, { ReactNode } from "react";
33

4+
import { useCustomSettings } from "../../CustomSettingsContext";
45
import { RtqMonitoringTaskMeta } from "../../Domain/Api/RtqMonitoringTaskMeta";
56
import { Ticks } from "../../Domain/DataTypes/Time";
67
import { ticksToMilliseconds } from "../../Domain/Utils/ConvertTimeUtil";
@@ -34,6 +35,7 @@ export const TaskDetailsMetaTable = ({
3435
childTaskIds,
3536
}: TaskDetailsMetaTableProps): JSX.Element => {
3637
const theme = React.useContext(ThemeContext);
38+
const { customStateCaptions, hideMissingMeta } = useCustomSettings();
3739

3840
const renderDate = (date?: Nullable<Ticks>): JSX.Element => (
3941
<span>
@@ -46,62 +48,32 @@ export const TaskDetailsMetaTable = ({
4648
</span>
4749
);
4850

49-
const renderMetaInfo = (): JSX.Element[] => {
51+
const renderRow = (name: string, value: Nullable<string>, render?: (x: Nullable<string>) => ReactNode) =>
52+
value || !hideMissingMeta ? (
53+
<tr key={name}>
54+
<td>{name}</td>
55+
<td data-tid={name}>{render ? render(value) : value}</td>
56+
</tr>
57+
) : null;
58+
59+
const renderMetaInfo = (): ReactNode[] => {
5060
const executionTime = ticksToMilliseconds(executionDurationTicks);
5161
return [
52-
<tr key="TaskId">
53-
<td>TaskId</td>
54-
<td data-tid="TaskId">
55-
<AllowCopyToClipboard>{id}</AllowCopyToClipboard>
56-
</td>
57-
</tr>,
58-
<tr key="State">
59-
<td>State</td>
60-
<td data-tid="State">{state}</td>
61-
</tr>,
62-
<tr key="Name">
63-
<td>Name</td>
64-
<td data-tid="Name">{name}</td>
65-
</tr>,
66-
<tr key="EnqueueTime">
67-
<td>EnqueueTime</td>
68-
<td data-tid="EnqueueTime">{renderDate(ticks)}</td>
69-
</tr>,
70-
<tr key="StartExecutingTime">
71-
<td>StartExecutingTime</td>
72-
<td data-tid="StartExecutingTime">{renderDate(startExecutingTicks)}</td>
73-
</tr>,
74-
<tr key="FinishExecutingTime">
75-
<td>FinishExecutingTime</td>
76-
<td data-tid="FinishExecutingTime">{renderDate(finishExecutingTicks)}</td>
77-
</tr>,
78-
<tr key="LastExecutionDurationInMs">
79-
<td>LastExecutionDurationInMs</td>
80-
<td data-tid="LastExecutionDurationInMs">{executionTime == null ? "unknown" : executionTime}</td>
81-
</tr>,
82-
<tr key="MinimalStartTime">
83-
<td>MinimalStartTime</td>
84-
<td data-tid="MinimalStartTime">{renderDate(minimalStartTicks)}</td>
85-
</tr>,
86-
<tr key="ExpirationTime">
87-
<td>ExpirationTime</td>
88-
<td data-tid="ExpirationTime">{renderDate(expirationTimestampTicks)}</td>
89-
</tr>,
90-
<tr key="ExpirationModificationTime">
91-
<td>ExpirationModificationTime</td>
92-
<td data-tid="ExpirationModificationTime">{renderDate(expirationModificationTicks)}</td>
93-
</tr>,
94-
<tr key="LastModificationTime">
95-
<td>LastModificationTime</td>
96-
<td data-tid="LastModificationTime">{renderDate(lastModificationTicks)}</td>
97-
</tr>,
98-
<tr key="Attempts">
99-
<td>Attempts</td>
100-
<td data-tid="Attempts">{attempts}</td>
101-
</tr>,
102-
<tr key="ParentTaskId">
103-
<td>ParentTaskId</td>
104-
<td data-tid="ParentTaskId">
62+
renderRow("TaskId", id, id => <AllowCopyToClipboard>{id}</AllowCopyToClipboard>),
63+
renderRow("State", customStateCaptions[state]),
64+
renderRow("Name", name),
65+
renderRow("EnqueueTime", ticks, renderDate),
66+
renderRow("StartExecutingTime", startExecutingTicks, renderDate),
67+
renderRow("FinishExecutingTime", finishExecutingTicks, renderDate),
68+
renderRow("LastExecutionDurationInMs", executionTime, executionTime => executionTime || "unknown"),
69+
renderRow("MinimalStartTime", minimalStartTicks, renderDate),
70+
renderRow("ExpirationTime", expirationTimestampTicks, renderDate),
71+
renderRow("ExpirationModificationTime", expirationModificationTicks, renderDate),
72+
renderRow("LastModificationTime", lastModificationTicks, renderDate),
73+
renderRow("Attempts", attempts.toString()),
74+
<tr key={"ParentTaskId"}>
75+
<td>{"ParentTaskId"}</td>
76+
<td data-tid={"ParentTaskId"}>
10577
{parentTaskId && <RouterLink to={`../${parentTaskId}`}>{parentTaskId}</RouterLink>}
10678
</td>
10779
</tr>,

cassandra-distributed-task-queue-ui/src/components/TaskDetailsPage/TaskDetailsPage.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import { Button, Link, Modal, ThemeContext } from "@skbkontur/react-ui";
66
import React from "react";
77
import { Location } from "react-router-dom";
88

9+
import { useCustomSettings } from "../../CustomSettingsContext";
910
import { RtqMonitoringTaskModel } from "../../Domain/Api/RtqMonitoringTaskModel";
10-
import { ICustomRenderer } from "../../Domain/CustomRenderer";
1111
import { cancelableStates, rerunableStates } from "../../Domain/TaskStateExtensions";
1212
import { searchRequestMapping } from "../../containers/TasksPageContainer";
1313
import { Accordion } from "../Accordion/Accordion";
@@ -21,7 +21,6 @@ import { jsStyles } from "./TaskDetailsPage.styles";
2121
export interface TaskDetailsPageProps {
2222
parentLocation: string;
2323
taskDetails: Nullable<RtqMonitoringTaskModel>;
24-
customRenderer: ICustomRenderer;
2524
getTaskLocation: (id: string) => string | Partial<Location>;
2625
allowRerunOrCancel: boolean;
2726
onRerun: (id: string) => void;
@@ -31,7 +30,6 @@ export interface TaskDetailsPageProps {
3130
export function TaskDetailsPage({
3231
parentLocation,
3332
taskDetails,
34-
customRenderer,
3533
getTaskLocation,
3634
allowRerunOrCancel,
3735
onRerun,
@@ -40,6 +38,7 @@ export function TaskDetailsPage({
4038
const [openedModal, setOpenedModal] = React.useState(false);
4139
const [modalType, setModalType] = React.useState<"Cancel" | "Rerun">("Cancel");
4240
const theme = React.useContext(ThemeContext);
41+
const { customDetailRenderer } = useCustomSettings();
4342

4443
const rerun = () => {
4544
setOpenedModal(true);
@@ -59,7 +58,7 @@ export function TaskDetailsPage({
5958
}
6059
const isCancelable = cancelableStates.includes(taskDetails.taskMeta.state);
6160
const isRerunable = rerunableStates.includes(taskDetails.taskMeta.state);
62-
const relatedTasksRequest = customRenderer.getRelatedTasksLocation(taskDetails);
61+
const relatedTasksRequest = customDetailRenderer.getRelatedTasksLocation(taskDetails);
6362
if (!isCancelable && !isRerunable && relatedTasksRequest == null) {
6463
return null;
6564
}
@@ -183,7 +182,7 @@ export function TaskDetailsPage({
183182
<Fit className={jsStyles.taskDataContainer()}>
184183
<Accordion
185184
renderCaption={null}
186-
renderValue={customRenderer.renderDetails}
185+
renderValue={customDetailRenderer.renderDetails}
187186
value={taskDetails.taskData}
188187
title="TaskData"
189188
/>

0 commit comments

Comments
 (0)