Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gafetinov/upgrade for diadoc #39

Merged
merged 7 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## v3.1.0 - 2023.12.05
- add multiple choice for tasks
- add prop for custom status names
- add prop for hiding null data in meta table
- add prop for custom search help
- small update of layout

## v3.0.0 - 2023.10.23
- Add new bundler Vite instead of WebPack
- Update Node to v20
Expand Down
3 changes: 2 additions & 1 deletion cassandra-distributed-task-queue-ui/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@
"@typescript-eslint/explicit-member-accessibility": "error",
"@typescript-eslint/explicit-function-return-type": "off",
"react/no-deprecated": "warn",
"react/prop-types": "off"
"react/prop-types": "off",
"react/display-name": "warn"
},
"ignorePatterns": ["dist/", "react-selenium-testing.js"],
"settings": {
Expand Down
57 changes: 57 additions & 0 deletions cassandra-distributed-task-queue-ui/src/CustomSettingsContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { createContext, PropsWithChildren, useContext } from "react";
import type { JSX } from "react";

import { TaskState } from "./Domain/Api/TaskState";
import { CustomRenderer, ICustomRenderer } from "./Domain/CustomRenderer";

const TaskStateCaptions = {
[TaskState.Unknown]: "Unknown",
[TaskState.New]: "New",
[TaskState.WaitingForRerun]: "Waiting for rerun",
[TaskState.WaitingForRerunAfterError]: "Waiting for rerun after error",
[TaskState.Finished]: "Finished",
[TaskState.InProcess]: "In process",
[TaskState.Fatal]: "Fatal",
[TaskState.Canceled]: "Canceled",
};

export type TaskStateDict = Partial<Record<TaskState, string>>;
ArtyMgn marked this conversation as resolved.
Show resolved Hide resolved

export interface ICustomSettings {
customDetailRenderer: ICustomRenderer;
customStateCaptions: TaskStateDict;
hideMissingMeta: boolean;
customSearchHelp?: JSX.Element;
}

const defaultValue: ICustomSettings = {
customStateCaptions: TaskStateCaptions,
customDetailRenderer: new CustomRenderer(),
hideMissingMeta: false,
};

const CustomSettingsContext = createContext<ICustomSettings>(defaultValue);

export const CustomSettingsProvider = ({

This comment was marked as resolved.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

его и таскать везде проще, он уже много где прокинут, не нужен будет новый контекст

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не захотелось их в один класс потому что это независящие друг от друга штуки.
И в edi они не нужны, если их в класс положить, то придется все равно в edi прописывать эти методы после обновления. А так можно просто обновиться и не париться.
А по поводу контекста, хотелось убрать лишние прокидывания пропсов

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

независящие, но они в целом про одно и то же: кастомизацию для ui очереди задач

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

в целом и так сойдет конечно

customStateCaptions,
customSearchHelp,
customDetailRenderer,
hideMissingMeta,
children,
}: PropsWithChildren<Partial<ICustomSettings>>) => {
const stateCaptions = customStateCaptions || TaskStateCaptions;
const renderer = customDetailRenderer || new CustomRenderer();
return (
<CustomSettingsContext.Provider
value={{
customStateCaptions: stateCaptions,
customDetailRenderer: renderer,
customSearchHelp,
hideMissingMeta: !!hideMissingMeta,
}}>
{children}
</CustomSettingsContext.Provider>
);
};

export const useCustomSettings = () => useContext(CustomSettingsContext);
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isValid, parse as parseDateInternal } from "date-fns";
import { endOfDay, isValid, parse as parseDateInternal, startOfDay } from "date-fns";
import difference from "lodash/difference";

import { DateTimeRange } from "../DataTypes/DateTimeRange";
Expand Down Expand Up @@ -147,8 +147,8 @@ export class DateTimeRangeMapper {
return this.defaultValue;
}
return {
lowerBound: lowerBound,
upperBound: upperBound,
lowerBound: lowerBound && startOfDay(lowerBound),
upperBound: upperBound && endOfDay(upperBound),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function createDefaultRemoteTaskQueueSearchRequest(): RtqMonitoringSearch
}

export function isRemoteTaskQueueSearchRequestEmpty(searchRequest: Nullable<RtqMonitoringSearchRequest>): boolean {
if (searchRequest === null || searchRequest === undefined) {
if (!searchRequest) {
return true;
}
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import Decimal from "decimal.js";

export function ticksToMilliseconds(timeStr: Nullable<string>): Nullable<number> {
export function ticksToMilliseconds(timeStr: Nullable<string>): Nullable<string> {
if (!timeStr) {
return null;
}
const commonTime = new Decimal(timeStr);
return commonTime.div(10000).toNumber();
return commonTime.div(10000).toString();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { JSX } from "react";
import { Routes, Route } from "react-router-dom";

import { CustomSettingsProvider, TaskStateDict } from "./CustomSettingsContext";
import { IRtqMonitoringApi } from "./Domain/Api/RtqMonitoringApi";
import { ICustomRenderer } from "./Domain/CustomRenderer";
import { TaskChainsTreeContainer } from "./containers/TaskChainsTreeContainer";
Expand All @@ -11,44 +13,55 @@ interface RemoteTaskQueueApplicationProps {
customRenderer: ICustomRenderer;
useErrorHandlingContainer: boolean;
isSuperUser: boolean;
customStateCaptions?: TaskStateDict;
customSearchHelp?: JSX.Element;
hideMissingMeta?: boolean;
}

export const RemoteTaskQueueApplication = ({
isSuperUser,
rtqMonitoringApi,
customRenderer,
useErrorHandlingContainer,
customRenderer,
customStateCaptions,
customSearchHelp,
hideMissingMeta,
}: RemoteTaskQueueApplicationProps): JSX.Element => (
<Routes>
<Route
path="/"
element={
<TasksPageContainer
isSuperUser={isSuperUser}
rtqMonitoringApi={rtqMonitoringApi}
useErrorHandlingContainer={useErrorHandlingContainer}
/>
}
/>
<Route
path="Tree"
element={
<TaskChainsTreeContainer
rtqMonitoringApi={rtqMonitoringApi}
useErrorHandlingContainer={useErrorHandlingContainer}
/>
}
/>
<Route
path=":id"
element={
<TaskDetailsPageContainer
isSuperUser={isSuperUser}
rtqMonitoringApi={rtqMonitoringApi}
customRenderer={customRenderer}
useErrorHandlingContainer={useErrorHandlingContainer}
/>
}
/>
</Routes>
<CustomSettingsProvider
customStateCaptions={customStateCaptions}
customSearchHelp={customSearchHelp}
customDetailRenderer={customRenderer}
hideMissingMeta={hideMissingMeta}>
<Routes>
<Route
path="/"
element={
<TasksPageContainer
isSuperUser={isSuperUser}
rtqMonitoringApi={rtqMonitoringApi}
useErrorHandlingContainer={useErrorHandlingContainer}
/>
}
/>
<Route
path="Tree"
element={
<TaskChainsTreeContainer
rtqMonitoringApi={rtqMonitoringApi}
useErrorHandlingContainer={useErrorHandlingContainer}
/>
}
/>
<Route
path=":id"
element={
<TaskDetailsPageContainer
isSuperUser={isSuperUser}
rtqMonitoringApi={rtqMonitoringApi}
useErrorHandlingContainer={useErrorHandlingContainer}
/>
}
/>
</Routes>
</CustomSettingsProvider>
);
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ThemeContext } from "@skbkontur/react-ui";
import React from "react";
import React, { ReactNode } from "react";

import { useCustomSettings } from "../../CustomSettingsContext";
import { RtqMonitoringTaskMeta } from "../../Domain/Api/RtqMonitoringTaskMeta";
import { Ticks } from "../../Domain/DataTypes/Time";
import { ticksToMilliseconds } from "../../Domain/Utils/ConvertTimeUtil";
Expand Down Expand Up @@ -34,6 +35,7 @@ export const TaskDetailsMetaTable = ({
childTaskIds,
}: TaskDetailsMetaTableProps): JSX.Element => {
const theme = React.useContext(ThemeContext);
const { customStateCaptions, hideMissingMeta } = useCustomSettings();

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

const renderMetaInfo = (): JSX.Element[] => {
const renderRow = (name: string, value: Nullable<string>, render?: (x: Nullable<string>) => ReactNode) =>
value || !hideMissingMeta ? (
<tr key={name}>
<td>{name}</td>
<td data-tid={name}>{render ? render(value) : value}</td>
</tr>
) : null;

const renderMetaInfo = (): ReactNode[] => {
const executionTime = ticksToMilliseconds(executionDurationTicks);
return [
<tr key="TaskId">
<td>TaskId</td>
<td data-tid="TaskId">
<AllowCopyToClipboard>{id}</AllowCopyToClipboard>
</td>
</tr>,
<tr key="State">
<td>State</td>
<td data-tid="State">{state}</td>
</tr>,
<tr key="Name">
<td>Name</td>
<td data-tid="Name">{name}</td>
</tr>,
<tr key="EnqueueTime">
<td>EnqueueTime</td>
<td data-tid="EnqueueTime">{renderDate(ticks)}</td>
</tr>,
<tr key="StartExecutingTime">
<td>StartExecutingTime</td>
<td data-tid="StartExecutingTime">{renderDate(startExecutingTicks)}</td>
</tr>,
<tr key="FinishExecutingTime">
<td>FinishExecutingTime</td>
<td data-tid="FinishExecutingTime">{renderDate(finishExecutingTicks)}</td>
</tr>,
<tr key="LastExecutionDurationInMs">
<td>LastExecutionDurationInMs</td>
<td data-tid="LastExecutionDurationInMs">{executionTime == null ? "unknown" : executionTime}</td>
</tr>,
<tr key="MinimalStartTime">
<td>MinimalStartTime</td>
<td data-tid="MinimalStartTime">{renderDate(minimalStartTicks)}</td>
</tr>,
<tr key="ExpirationTime">
<td>ExpirationTime</td>
<td data-tid="ExpirationTime">{renderDate(expirationTimestampTicks)}</td>
</tr>,
<tr key="ExpirationModificationTime">
<td>ExpirationModificationTime</td>
<td data-tid="ExpirationModificationTime">{renderDate(expirationModificationTicks)}</td>
</tr>,
<tr key="LastModificationTime">
<td>LastModificationTime</td>
<td data-tid="LastModificationTime">{renderDate(lastModificationTicks)}</td>
</tr>,
<tr key="Attempts">
<td>Attempts</td>
<td data-tid="Attempts">{attempts}</td>
</tr>,
<tr key="ParentTaskId">
<td>ParentTaskId</td>
<td data-tid="ParentTaskId">
renderRow("TaskId", id, id => <AllowCopyToClipboard>{id}</AllowCopyToClipboard>),
renderRow("State", customStateCaptions[state]),
renderRow("Name", name),
renderRow("EnqueueTime", ticks, renderDate),
renderRow("StartExecutingTime", startExecutingTicks, renderDate),
renderRow("FinishExecutingTime", finishExecutingTicks, renderDate),
renderRow("LastExecutionDurationInMs", executionTime, executionTime => executionTime || "unknown"),
renderRow("MinimalStartTime", minimalStartTicks, renderDate),
renderRow("ExpirationTime", expirationTimestampTicks, renderDate),
renderRow("ExpirationModificationTime", expirationModificationTicks, renderDate),
renderRow("LastModificationTime", lastModificationTicks, renderDate),
renderRow("Attempts", attempts.toString()),
<tr key={"ParentTaskId"}>
<td>{"ParentTaskId"}</td>
<td data-tid={"ParentTaskId"}>
{parentTaskId && <RouterLink to={`../${parentTaskId}`}>{parentTaskId}</RouterLink>}
</td>
</tr>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { Button, Link, Modal, ThemeContext } from "@skbkontur/react-ui";
import React from "react";
import { Location } from "react-router-dom";

import { useCustomSettings } from "../../CustomSettingsContext";
import { RtqMonitoringTaskModel } from "../../Domain/Api/RtqMonitoringTaskModel";
import { ICustomRenderer } from "../../Domain/CustomRenderer";
import { cancelableStates, rerunableStates } from "../../Domain/TaskStateExtensions";
import { searchRequestMapping } from "../../containers/TasksPageContainer";
import { Accordion } from "../Accordion/Accordion";
Expand All @@ -21,7 +21,6 @@ import { jsStyles } from "./TaskDetailsPage.styles";
export interface TaskDetailsPageProps {
parentLocation: string;
taskDetails: Nullable<RtqMonitoringTaskModel>;
customRenderer: ICustomRenderer;
getTaskLocation: (id: string) => string | Partial<Location>;
allowRerunOrCancel: boolean;
onRerun: (id: string) => void;
Expand All @@ -31,7 +30,6 @@ export interface TaskDetailsPageProps {
export function TaskDetailsPage({
parentLocation,
taskDetails,
customRenderer,
getTaskLocation,
allowRerunOrCancel,
onRerun,
Expand All @@ -40,6 +38,7 @@ export function TaskDetailsPage({
const [openedModal, setOpenedModal] = React.useState(false);
const [modalType, setModalType] = React.useState<"Cancel" | "Rerun">("Cancel");
const theme = React.useContext(ThemeContext);
const { customDetailRenderer } = useCustomSettings();

const rerun = () => {
setOpenedModal(true);
Expand All @@ -59,7 +58,7 @@ export function TaskDetailsPage({
}
const isCancelable = cancelableStates.includes(taskDetails.taskMeta.state);
const isRerunable = rerunableStates.includes(taskDetails.taskMeta.state);
const relatedTasksRequest = customRenderer.getRelatedTasksLocation(taskDetails);
const relatedTasksRequest = customDetailRenderer.getRelatedTasksLocation(taskDetails);
if (!isCancelable && !isRerunable && relatedTasksRequest == null) {
return null;
}
Expand Down Expand Up @@ -183,7 +182,7 @@ export function TaskDetailsPage({
<Fit className={jsStyles.taskDataContainer()}>
<Accordion
renderCaption={null}
renderValue={customRenderer.renderDetails}
renderValue={customDetailRenderer.renderDetails}
value={taskDetails.taskData}
title="TaskData"
/>
Expand Down
Loading
Loading