Skip to content
This repository was archived by the owner on Aug 27, 2026. It is now read-only.
Open
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
159 changes: 105 additions & 54 deletions packages/react-components/src/Jobs/JobList/JobList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
Toolbar,
VirtualTable,
} from '@devexpress/dx-react-grid-material-ui';
import { Paper } from '@material-ui/core';
import { Paper, Switch, Typography } from '@material-ui/core';
import { HubConnectionBuilder, LogLevel } from '@microsoft/signalr';
import React, { useEffect, useRef, useState, useCallback } from 'react';
import { executeJobQuery, fetchLogs } from '../../api';
Expand All @@ -29,7 +29,7 @@ import { DateFilter } from '../../common/DateFilter/DateFilter';
import { Cell, dateGroupCriteria, GroupCellContent } from './helpers/helpers';
import JobDetail from './helpers/JobDetail';
import { JobPanelStyles } from './styles';
import JobListProps, { JobData } from './types';
import JobListProps, { JobData, Sorting } from './types';
import { DateProps } from '../../common/types';

const DEFAULT_COLUMNS = [
Expand All @@ -47,7 +47,18 @@ const DEFAULT_COLUMNS = [
const NOTIFICATION_HUB = '/notificationhub';

const JobList = (props: JobListProps) => {
const { dataSources, disabledColumns, parameters, startTimeUtc, dateTimeFormat, timeZone, defaultFilter } = props;
const {
dataSources,
disabledColumns,
parameters,
startTimeUtc,
dateTimeFormat,
timeZone,
defaultFilter,
positionToInsert,
showHidePrefixButton,
} = props;

const initialDateState = {
from: new Date(startTimeUtc).toISOString(),
to: new Date().toISOString(),
Expand Down Expand Up @@ -79,6 +90,8 @@ const JobList = (props: JobListProps) => {
const [windowHeight, setWindowHeight] = useState<number>(window.innerHeight);
const [date, setDate] = useState<DateProps>(initialDateState);
const [selectedRow, setSelectedRow] = useState<string>('');
const [sorting, setSorting] = useState<Sorting[]>([{ columnName: 'requested', direction: 'desc' }]);
const [hideWorkflowPrefix, setHideWorkflowPrefix] = useState(false);
const [tableColumnExtensions] = useState([{ columnName: 'status', width: 120 }]);
const latestJobs = useRef(null);

Expand All @@ -99,7 +112,7 @@ const JobList = (props: JobListProps) => {
]);

const durationToSeconds = (duration: string | null): number => {
if (duration === '' || duration === null ) {
if (duration === '' || duration === null) {
return 0;
}

Expand All @@ -109,7 +122,7 @@ const JobList = (props: JobListProps) => {
if (parts[index].includes('h')) {
seconds += Number(parts[index].slice(0, -1)) * 3600;;
}

if (parts[index].includes('m')) {
seconds += Number(parts[index].slice(0, -1)) * 60;
}
Expand All @@ -135,7 +148,7 @@ const JobList = (props: JobListProps) => {
{ columnName: 'duration', compare: compareDurations },
{ columnName: 'delay', compare: compareDurations },
]);

const fetchJobList = () => {
setLoading(true);

Expand Down Expand Up @@ -193,18 +206,26 @@ const JobList = (props: JobListProps) => {

const parameterHeader = parameters
? parameters.reduce(
(acc, cur) => [
...acc,
{
title: cur.label,
name: cur.parameter,
},
],
[],
)
(acc, cur) => [
...acc,
{
title: cur.label,
name: cur.parameter,
},
],
[],
)
: [];

const [columns] = useState(DEFAULT_COLUMNS.concat(parameterHeader));
const combinedColumns = typeof positionToInsert === "undefined"
? [...DEFAULT_COLUMNS, ...parameterHeader]
: [
...DEFAULT_COLUMNS.slice(0, positionToInsert),
...parameterHeader,
...DEFAULT_COLUMNS.slice(positionToInsert)
];

const [columns] = useState(combinedColumns);

const expandWithData = (row) => {
const {
Expand Down Expand Up @@ -307,17 +328,39 @@ const JobList = (props: JobListProps) => {
const ToolbarRootComponent = useCallback((props: any) => (
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: 10 }}>
<div style={{ display: 'flex', flexDirection: 'row-reverse', alignItems: 'center' }}>{props.children}</div>
<DateFilter
dateTimeFormat={dateTimeFormat}
startTimeUtc={startTimeUtc}
timeZone={timeZone}
date={date}
onSetDate={(date) => setDate(date)}
onClearDateFilter={clearDateFilter}
>
</DateFilter>
{showHidePrefixButton && (
<div style={{ display: 'flex' }}>
<div style={{ marginLeft: 20, display: 'flex', alignItems: 'center', width: '200px' }}>
<Typography style={{ fontSize: '15px' }}>Hide Workflow Prefix</Typography>
<Switch
checked={hideWorkflowPrefix}
onChange={(event) => setHideWorkflowPrefix(event.target.checked)}
/>
</div>
<DateFilter
dateTimeFormat={dateTimeFormat}
startTimeUtc={startTimeUtc}
timeZone={timeZone}
date={date}
onSetDate={(date) => setDate(date)}
onClearDateFilter={clearDateFilter}
>
</DateFilter>
</div>
)}
{!showHidePrefixButton && (
<DateFilter
dateTimeFormat={dateTimeFormat}
startTimeUtc={startTimeUtc}
timeZone={timeZone}
date={date}
onSetDate={(date) => setDate(date)}
onClearDateFilter={clearDateFilter}
>
</DateFilter>
)}
</div>
),[]);
), [hideWorkflowPrefix]);

const jobUpdated = (job) => {
const dataUpdated = JSON.parse(job.data);
Expand All @@ -327,29 +370,29 @@ const JobList = (props: JobListProps) => {
const updatedJob = jobs.map((job) =>
job.id === dataUpdated.Id
? {
...job,
started:
job.started || dataUpdated.Started ? zonedTimeFromUTC(dataUpdated.Started, timeZone, dateTimeFormat) : '',
finished:
job.finished || dataUpdated.Finished
? zonedTimeFromUTC(dataUpdated.Finished, timeZone, dateTimeFormat)
: '',
hostId: dataUpdated.HostId,
status: dataUpdated.Status,
duration:
job.duration ||
(dataUpdated.Started &&
dataUpdated.Finished &&
calcTimeDifference(dataUpdated.Started.split('.')[0], dataUpdated.Finished.split('.')[0])),
delay:
job.delay ||
(dataUpdated.Started &&
calcTimeDifference(dataUpdated.Requested.split('.')[0], dataUpdated.Started.split('.')[0])),
progress: dataUpdated.Progress || 0,
tokenJobLog: dataSources[0].tokenJobLog || '', // So wrong ... it doesn't necessarily sit on the first one. Should be fixed later
hostJobLog: dataSources[0].hostJobLog || '',
connectionJobLog: dataSources[0].connectionJobLog || '',
}
...job,
started:
job.started || dataUpdated.Started ? zonedTimeFromUTC(dataUpdated.Started, timeZone, dateTimeFormat) : '',
finished:
job.finished || dataUpdated.Finished
? zonedTimeFromUTC(dataUpdated.Finished, timeZone, dateTimeFormat)
: '',
hostId: dataUpdated.HostId,
status: dataUpdated.Status,
duration:
job.duration ||
(dataUpdated.Started &&
dataUpdated.Finished &&
calcTimeDifference(dataUpdated.Started.split('.')[0], dataUpdated.Finished.split('.')[0])),
delay:
job.delay ||
(dataUpdated.Started &&
calcTimeDifference(dataUpdated.Requested.split('.')[0], dataUpdated.Started.split('.')[0])),
progress: dataUpdated.Progress || 0,
tokenJobLog: dataSources[0].tokenJobLog || '', // So wrong ... it doesn't necessarily sit on the first one. Should be fixed later
hostJobLog: dataSources[0].hostJobLog || '',
connectionJobLog: dataSources[0].connectionJobLog || '',
}
: job,
);

Expand All @@ -360,7 +403,7 @@ const JobList = (props: JobListProps) => {
const dataAdded = JSON.parse(job.data);
const jobs = [...latestJobs.current];
console.log({ dataAdded });

const addedJob = {
taskId: dataAdded.TaskId,
id: dataAdded.Id,
Expand Down Expand Up @@ -409,10 +452,18 @@ const JobList = (props: JobListProps) => {
);
})
.catch((e) => console.log('Connection failed: ', e));

return connection;
};

const handleGroupingChange = (grouping) => {
console.log('grouping', grouping)
if (grouping.length > 0) {
const lastGroupedColumn = grouping[grouping.length - 1].columnName;
setSorting([{ columnName: lastGroupedColumn, direction: 'asc' }]);
}
};

useEffect(() => {
const handleResize = () => {
setWindowHeight(window.innerHeight);
Expand All @@ -438,17 +489,17 @@ const JobList = (props: JobListProps) => {
<FilteringState defaultFilters={defaultFilter} />
<IntegratedFiltering />

<SortingState defaultSorting={[{ columnName: 'requested', direction: 'desc' }]} />
<SortingState sorting={sorting} onSortingChange={setSorting} />
<IntegratedSorting columnExtensions={integratedSortingColumnExtensions} />

<DragDropProvider />
<GroupingState />
<GroupingState onGroupingChange={handleGroupingChange} />
<IntegratedGrouping columnExtensions={integratedGroupingColumnExtensions} />

<VirtualTable
height={windowHeight - 230}
rowComponent={TableRow}
cellComponent={Cell}
cellComponent={(cellProps) => <Cell {...cellProps} hideWorkflowPrefix={hideWorkflowPrefix} />}
columnExtensions={tableColumnExtensions}
/>

Expand Down
30 changes: 26 additions & 4 deletions packages/react-components/src/Jobs/JobList/helpers/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,24 @@ export const GroupCellContent = (props: any) => (
);

export const Cell = (props: any) => {
if (props.column.name === 'status') {
const { column, row, hideWorkflowPrefix } = props;

if (column.name === 'status') {
return (
<td className="MuiTableCell-root">
<StatusCell {...props} />
</td>
);
}

if (props.column.name === 'delay') {
const { requested, started } = props.row;
if (column.name === 'delay') {
const { requested, started } = row;

if (!requested && !started) {
return <td className="MuiTableCell-root"></td>;
}

const differenceMinutes = differenceInMinutes(new Date(props.row.started), new Date(props.row.requested));
const differenceMinutes = differenceInMinutes(new Date(row.started), new Date(row.requested));

let delayColor = '';

Expand All @@ -49,6 +51,26 @@ export const Cell = (props: any) => {
);
}

if (column.name === 'taskId' && hideWorkflowPrefix && props.value.startsWith('workflow')) {
const adjustedValue = props.value.replace('workflow', ' ');

return (
<td className="MuiTableCell-root">
<div style={{
padding: '8px',
textOverflow: 'ellipsis',
overflow: 'hidden'
}}>
<Typography variant='body2' style={{
paddingLeft: 10
}}>
{adjustedValue}
</Typography>
</div>
</td>
);
}

return <VirtualTable.Cell {...props} />;
};

Expand Down
10 changes: 9 additions & 1 deletion packages/react-components/src/Jobs/JobList/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ interface JobListProps {
defaultFilter?: Filter[];
/** Data source to get the logs specific parameters */
parameters?: Parameters[];
/** Spesific paremeters position */
positionToInsert?: number;
/** The date time format that the dates shown in */
dateTimeFormat: string;
/** Selected date for log entries from */
Expand All @@ -26,6 +28,9 @@ interface JobListProps {
};
/** Emit event to client when jobs received from the server */
onReceived?: (data: any) => void;
/** Hide Prefix Workflow Task Id */
showHidePrefixButton?: boolean

}

interface Parameters {
Expand Down Expand Up @@ -106,5 +111,8 @@ interface DateFilterProps {
onClearDateFilter: () => void;
}

type SortingDirection = 'asc' | 'desc';
type Sorting = { columnName: string; direction: SortingDirection; };

export default JobListProps;
export { JobData, FilterProps, JobDetailProps, DateFilterProps, Parameters };
export { JobData, FilterProps, JobDetailProps, DateFilterProps, Parameters, Sorting };
6 changes: 5 additions & 1 deletion packages/react-components/src/Jobs/Jobs.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const JobListStory = () => {
} as DataSource,
];

const disabledColumns = ['accountId', 'Area'];
const disabledColumns = ['accountId'];

const defaultFilter = [{columnName: 'taskId', operation: 'contains', value: 'workflow'}]

Expand All @@ -34,6 +34,8 @@ export const JobListStory = () => {
},
];

const positionToInsert = 1

return (
<LoginGate host={process.env.ENDPOINT_URL!} showRememberMe={true} textFieldVariant={'outlined'}>
{({ token: { accessToken } }) => (
Expand All @@ -49,9 +51,11 @@ export const JobListStory = () => {
noEntriesData: 'Tidak ada entri job',
noEntriesFilter: 'Tidak ada entri job untuk status job yang dipilih',
}}
positionToInsert={positionToInsert}
onReceived={(data) => {
console.log(data);
}}
showHidePrefixButton={true}
/>
)}
</LoginGate>
Expand Down