Skip to content

Commit 9479147

Browse files
committed
feat: allows DatePicker, improve performance and review suggestions
1 parent bf70696 commit 9479147

30 files changed

Lines changed: 691 additions & 404 deletions

packages/diracx-web-components/.storybook/main.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ const config: StorybookConfig = {
4242
"../../hooks/metadata": require.resolve(
4343
"../stories/mocks/metadata.mock.tsx",
4444
),
45-
"./JobDataService": require.resolve(
46-
"../stories/mocks/JobDataService.mock.tsx",
45+
"./jobDataService": require.resolve(
46+
"../stories/mocks/jobDataService.mock.ts",
4747
),
4848
};
4949
return config;

packages/diracx-web-components/eslint.config.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ export default [
6464
"react/prop-types": "off",
6565
"react/react-in-jsx-scope": "off",
6666
"react/destructuring-assignment": ["error", "always"],
67+
"@typescript-eslint/no-unused-vars": [
68+
"error",
69+
{
70+
argsIgnorePattern: "^_",
71+
varsIgnorePattern: "^_",
72+
caughtErrorsIgnorePattern: "^_",
73+
ignoreRestSiblings: true,
74+
},
75+
],
6776
"no-restricted-properties": [
6877
"error",
6978
{

packages/diracx-web-components/jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const config = {
1313
moduleNameMapper: {
1414
"^@axa-fr/react-oidc$": "<rootDir>/stories/mocks/react-oidc.mock.tsx",
1515
"^../../hooks/metadata$": "<rootDir>/stories/mocks/metadata.mock.tsx",
16-
"^./JobDataService$": "<rootDir>/stories/mocks/JobDataService.mock.tsx",
16+
"^./jobDataService$": "<rootDir>/stories/mocks/jobDataService.mock.ts",
1717
},
1818
};
1919

packages/diracx-web-components/src/components/JobMonitor/JobDataTable.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import {
3535
refreshJobs,
3636
rescheduleJobs,
3737
useJobs,
38-
} from "./JobDataService";
38+
} from "./jobDataService";
3939

4040
/**
4141
* Job Data Table props

packages/diracx-web-components/src/components/JobMonitor/JobMonitor.tsx

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
RowSelectionState,
2121
VisibilityState,
2222
PaginationState,
23+
ColumnDef,
2324
} from "@tanstack/react-table";
2425

2526
import { useApplicationId } from "../../hooks/application";
@@ -126,7 +127,7 @@ export default function JobMonitor() {
126127
setSearchBody((prev) => ({
127128
...prev,
128129
search: filters.map(({ parameter, operator, value, values }) => ({
129-
parameter: fromHumanReadableText(parameter),
130+
parameter: fromHumanReadableText(parameter, columns),
130131
operator,
131132
value,
132133
values,
@@ -202,7 +203,7 @@ export default function JobMonitor() {
202203
id: "Status",
203204
header: "Status",
204205
cell: (info) => renderStatusCell(info.getValue()),
205-
meta: { type: "category", values: Object.keys(statusColors).sort() },
206+
meta: { type: "string", values: Object.keys(statusColors).sort() },
206207
}),
207208
columnHelper.accessor("MinorStatus", {
208209
id: "MinorStatus",
@@ -270,6 +271,11 @@ export default function JobMonitor() {
270271
header: "User Priority",
271272
meta: { type: "number" },
272273
}),
274+
columnHelper.accessor("RescheduleCounter", {
275+
id: "RescheduleCounter",
276+
header: "Reschedule Counter",
277+
meta: { type: "number" },
278+
}),
273279
],
274280
[columnHelper, renderStatusCell, statusColors],
275281
);
@@ -288,6 +294,7 @@ export default function JobMonitor() {
288294
setFilters={setFilters}
289295
searchBody={searchBody}
290296
handleApplyFilters={handleApplyFilters}
297+
columns={columns}
291298
/>
292299
<JobDataTable
293300
searchBody={searchBody}
@@ -358,35 +365,14 @@ export function validateAndConvertState(state: string): [string, boolean] {
358365
* @param name - The human-readable name of the job attribute
359366
* @returns The corresponding internal name of the job attribute
360367
*/
361-
export function fromHumanReadableText(name: string): string {
362-
switch (name) {
363-
case "ID":
364-
return "JobID";
365-
case "Minor Status":
366-
return "MinorStatus";
367-
case "Application Status":
368-
return "ApplicationStatus";
369-
case "Name":
370-
return "JobName";
371-
case "Job Group":
372-
return "JobGroup";
373-
case "Type":
374-
return "JobType";
375-
case "Last Update Time":
376-
return "LastUpdateTime";
377-
case "Last Sign of Life":
378-
return "HeartBeatTime";
379-
case "Submission Time":
380-
return "SubmissionTime";
381-
case "Owner Group":
382-
return "OwnerGroup";
383-
case "Start Execution Time":
384-
return "StartExecTime";
385-
case "End Execution Time":
386-
return "EndExecTime";
387-
case "User Priority":
388-
return "UserPriority";
389-
default:
390-
return name; // Return the original name if no match found
368+
export function fromHumanReadableText(
369+
name: string,
370+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
371+
columns: ColumnDef<Job, any>[],
372+
): string {
373+
const index = columns.findIndex((column) => column.header === name);
374+
if (index !== -1) {
375+
return columns[index].id || name; // Return the id if it exists, otherwise
391376
}
377+
return name;
392378
}
Lines changed: 60 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
11
"use client";
22

33
import { useEffect, useRef } from "react";
4-
4+
import { ColumnDef } from "@tanstack/react-table";
55
import { useOidcAccessToken } from "@axa-fr/react-oidc";
66
import { useOIDCContext } from "../../hooks/oidcConfiguration";
77
import { useDiracxUrl } from "../../hooks/utils";
8-
98
import { SearchBar } from "../shared/SearchBar/SearchBar";
10-
119
import {
1210
InternalFilter,
1311
JobSummary,
1412
SearchBarSuggestions,
1513
SearchBarToken,
1614
SearchBarTokenEquation,
1715
SearchBody,
16+
Job,
17+
Operators,
1818
} from "../../types";
19-
20-
import { getJobSummary } from "./JobDataService";
21-
19+
import { getJobSummary } from "./jobDataService";
2220
import { fromHumanReadableText } from "./JobMonitor";
2321

2422
interface JobSearchBarProps {
@@ -30,13 +28,17 @@ interface JobSearchBarProps {
3028
searchBody: SearchBody;
3129
/** The function to apply the filters */
3230
handleApplyFilters: () => void;
31+
/** The columns to display in the job monitor */
32+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
33+
columns: ColumnDef<Job, any>[];
3334
}
3435

3536
export function JobSearchBar({
3637
filters,
3738
searchBody,
3839
setFilters,
3940
handleApplyFilters,
41+
columns,
4042
}: JobSearchBarProps) {
4143
const { configuration } = useOIDCContext();
4244
const { accessToken } = useOidcAccessToken(configuration?.scope);
@@ -59,13 +61,16 @@ export function JobSearchBar({
5961
createSuggestions={(
6062
previousToken: SearchBarToken | undefined,
6163
previousEquation: SearchBarTokenEquation | undefined,
64+
equationIndex?: number,
6265
) =>
6366
createSuggestions(
6467
diracxUrl,
6568
accessToken,
6669
previousToken,
6770
previousEquation,
71+
columns,
6872
searchBody,
73+
equationIndex,
6974
)
7075
}
7176
allowKeyWordSearch={false} // Disable keyword search for job monitor
@@ -77,32 +82,46 @@ export function JobSearchBar({
7782
* Creates suggestions for the search bar based on the current tokens
7883
* If necessary, it fetches job summaries from the server to get personalized suggestions
7984
*
85+
* @param diracxUrl The URL of the DiracX server.
86+
* @param accessToken The access token for authentication, which can be undefined if not authenticated.
8087
* @param previousToken The previous token, which can be undefined if no token is focused.
8188
* @param previousEquation The previous equation, which can be undefined if no equation is focused.
82-
* @param data The data to be used for suggestions.
89+
* @param columns The columns to be used for suggestions, which are used to determine the categories and types.
90+
* @param searchBody The search body to be sent along with the request (optional).
91+
* @param searchBodyIndex The index of the search body, which is used to determine the current search context (optional).
8392
* @returns A list of suggestions based on the current tokens and data.
8493
*/
8594
async function createSuggestions(
8695
diracxUrl: string | null,
8796
accessToken: string | undefined,
8897
previousToken: SearchBarToken | undefined,
8998
previousEquation: SearchBarTokenEquation | undefined,
90-
searchBody?: SearchBody,
99+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
100+
columns: ColumnDef<Job, any>[],
101+
searchBody: SearchBody,
102+
searchBodyIndex?: number,
91103
): Promise<SearchBarSuggestions> {
92104
let data: JobSummary[] = [];
93105

106+
const search = [...(searchBody?.search || [])];
107+
108+
const newSearchBody = {
109+
...searchBody,
110+
search: search.slice(0, searchBodyIndex),
111+
};
112+
94113
const fetchJobSummary = async (category: string) => {
95114
if (diracxUrl && accessToken) {
96115
try {
97116
const result = await getJobSummary(
98117
diracxUrl,
99118
[category],
100119
accessToken,
101-
searchBody,
120+
newSearchBody,
102121
);
103122
data = result.data || [];
104123
} catch {
105-
console.error("Failed to fetch job summary");
124+
throw new Error("Failed to fetch job summary");
106125
}
107126
}
108127
};
@@ -114,48 +133,14 @@ async function createSuggestions(
114133
previousToken.type.startsWith("custom") ||
115134
previousToken.type === "value"
116135
) {
117-
// The categories to filter by and their types
136+
const items = columns.map((column) => column.header as string);
137+
const types = columns.map(
138+
(column) => `category_${column.meta?.type || "string"}`,
139+
);
140+
118141
return {
119-
items: [
120-
"Status",
121-
"Minor Status",
122-
"Application Status",
123-
"Site",
124-
"Type",
125-
"Job Group",
126-
"Owner",
127-
"Owner Group",
128-
"VO",
129-
"User Priority",
130-
"Reschedule Counter",
131-
"ID",
132-
"Submission Time",
133-
"Last Update Time",
134-
"Start Execution Time",
135-
"Last Sign of Life",
136-
"End Execution Time",
137-
"Name",
138-
],
139-
type: [
140-
"category_string",
141-
"category_string",
142-
"category_string",
143-
"category_string",
144-
"category_string",
145-
"category_string",
146-
"category_string",
147-
"category_string",
148-
"category_string",
149-
"category_number",
150-
"category_number",
151-
"category_number",
152-
"category_date",
153-
"category_date",
154-
"category_date",
155-
"category_date",
156-
"category_date",
157-
"category_string",
158-
],
142+
items: items,
143+
type: types,
159144
};
160145
}
161146

@@ -164,6 +149,7 @@ async function createSuggestions(
164149
// Load the suggestions for the selected category
165150
const category = fromHumanReadableText(
166151
previousEquation.items[0].label as string,
152+
columns,
167153
);
168154
await fetchJobSummary(category);
169155
const items = data.map(
@@ -188,47 +174,44 @@ async function createSuggestions(
188174
}
189175

190176
// else
191-
let suggestions: { items: string[]; type: string[] } = {
192-
items: [],
193-
type: [],
194-
};
177+
let items: string[] = [];
195178
switch (previousToken.type) {
196179
case "category_string":
197-
suggestions = {
198-
items: ["=", "!=", "like", "is in", "is not in"],
199-
type: Array(5).fill("operator_string"),
180+
items = Operators.getStringOperators().map((op) => op.getDisplay());
181+
return {
182+
items: items,
183+
type: Array(items.length).fill("operator_string"),
200184
};
201-
break;
202185
case "category_number":
203-
suggestions = {
204-
items: ["=", "!=", "<", ">", "is in", "is not in", "like"],
205-
type: Array(7).fill("operator_number"),
186+
items = Operators.getNumberOperators().map((op) => op.getDisplay());
187+
return {
188+
items: items,
189+
type: Array(items.length).fill("operator_number"),
206190
};
207-
break;
208191
case "category_boolean":
209-
suggestions = {
210-
items: ["=", "!="],
211-
type: Array(2).fill("operator_bool"),
192+
items = Operators.getBooleanOperators().map((op) => op.getDisplay());
193+
return {
194+
items: items,
195+
type: Array(items.length).fill("operator_bool"),
212196
};
213-
break;
214197
case "category_date":
215-
suggestions = {
216-
items: ["<", ">", "in the last"],
217-
type: Array(3).fill("operator_date"),
198+
items = Operators.getDateOperators().map((op) => op.getDisplay());
199+
return {
200+
items: items,
201+
type: Array(items.length).fill("operator_date"),
218202
};
219-
break;
220203
case "category":
221-
suggestions = {
222-
items: ["=", "!=", ">", "<", "like"],
223-
type: Array(5).fill("operator"),
204+
items = Operators.getDefaultOperators().map((op) => op.getDisplay());
205+
return {
206+
items: items,
207+
type: Array(items.length).fill("operator"),
224208
};
225-
break;
209+
226210
// We don't want suggestions for the number and in case of a custom token
227211
default:
228-
suggestions = {
212+
return {
229213
items: [],
230214
type: [],
231215
};
232216
}
233-
return suggestions;
234217
}

packages/diracx-web-components/src/components/JobMonitor/JobDataService.ts renamed to packages/diracx-web-components/src/components/JobMonitor/jobDataService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ export async function getJobSummary(
236236
searchBody?: SearchBody,
237237
): Promise<{ data: JobSummary[] }> {
238238
if (!diracxUrl) {
239-
throw new Error("Invalid URL generated for fetching job history.");
239+
throw new Error("Invalid URL generated for fetching job summary.");
240240
}
241241

242242
if (searchBody) processSearchBody(searchBody);

0 commit comments

Comments
 (0)