149 lines
4.8 KiB
TypeScript
149 lines
4.8 KiB
TypeScript
import * as React from 'react';
|
|
import { RouteStepFormModal } from './RouteStepFormModal';
|
|
import { ApprovalRouteApi } from '../../services/api';
|
|
import { RouteStepStatus, TemplateRoute, TemplateRouteStep } from '../../models';
|
|
import { routeStepStatusLabels, routeTypeLabels, texts } from '../../texts';
|
|
import { describeStepExecutor } from '../../utils/stepExecutor';
|
|
import { useRouteSteps } from '../../hooks/useRouteSteps';
|
|
import { useDeleteTarget } from '../../hooks/useDeleteTarget';
|
|
import {
|
|
ActionsCell,
|
|
Alert,
|
|
Badge,
|
|
Breadcrumbs,
|
|
Button,
|
|
ConfirmDialog,
|
|
DataTable,
|
|
IconButton,
|
|
PageHeader,
|
|
PrimaryCell
|
|
} from '../ui';
|
|
|
|
export interface IRouteStepsScreenProps {
|
|
api: ApprovalRouteApi;
|
|
route: TemplateRoute;
|
|
requestTypeName: string;
|
|
onBack: () => void;
|
|
}
|
|
|
|
export const RouteStepsScreen: React.FC<IRouteStepsScreenProps> = ({ api, route, requestTypeName, onBack }) => {
|
|
const steps = useRouteSteps(api, route.id);
|
|
const [savedWarning, setSavedWarning] = React.useState<string | undefined>();
|
|
|
|
const [editing, setEditing] = React.useState<TemplateRouteStep | undefined>();
|
|
const [showForm, setShowForm] = React.useState(false);
|
|
|
|
const deleteTarget = useDeleteTarget<TemplateRouteStep>(
|
|
item => api.templateRouteSteps.remove(route.id, item.id),
|
|
steps.reload
|
|
);
|
|
|
|
const openCreate = (): void => {
|
|
setEditing(undefined);
|
|
setShowForm(true);
|
|
};
|
|
|
|
const openEdit = (item: TemplateRouteStep): void => {
|
|
setEditing(item);
|
|
setShowForm(true);
|
|
};
|
|
|
|
const handleSaved = (savedStep: TemplateRouteStep): void => {
|
|
setSavedWarning(savedStep.warning ?? undefined);
|
|
steps.reload();
|
|
};
|
|
|
|
const nextOrderNo = steps.items.length > 0 ? Math.max(...steps.items.map(s => s.orderNo)) + 1 : 1;
|
|
|
|
return (
|
|
<div>
|
|
<Breadcrumbs
|
|
items={[
|
|
{ label: texts.common.home },
|
|
{ label: texts.routes.breadcrumb, onClick: onBack },
|
|
{ label: texts.routeSteps.breadcrumb(route.id) }
|
|
]}
|
|
/>
|
|
<PageHeader
|
|
icon="flag-check"
|
|
subtitle={texts.routeSteps.subtitle(requestTypeName, routeTypeLabels[route.routeType])}
|
|
title={texts.routeSteps.title(route.id)}
|
|
actions={
|
|
<>
|
|
<Button variant="ghost" icon="arrow-left" onClick={onBack}>{texts.routeSteps.back}</Button>
|
|
<Button variant="accent" icon="plus" onClick={openCreate}>{texts.routeSteps.add}</Button>
|
|
</>
|
|
}
|
|
/>
|
|
|
|
{savedWarning && <Alert kind="warn">{savedWarning}</Alert>}
|
|
{steps.error && <Alert kind="err">{steps.error}</Alert>}
|
|
{deleteTarget.error && <Alert kind="err">{deleteTarget.error}</Alert>}
|
|
|
|
<DataTable
|
|
columns={[
|
|
{ key: 'order', header: texts.routeSteps.columnOrderNo, width: '50px', render: r => r.orderNo },
|
|
{
|
|
key: 'executor',
|
|
header: texts.routeSteps.columnExecutor,
|
|
render: r => <PrimaryCell>{describeStepExecutor(r)}</PrimaryCell>
|
|
},
|
|
{
|
|
key: 'status',
|
|
header: texts.routeSteps.columnStatus,
|
|
render: r => (
|
|
<Badge variant={r.status === RouteStepStatus.Approval ? 'gold' : 'blue'}>
|
|
{routeStepStatusLabels[r.status]}
|
|
</Badge>
|
|
)
|
|
},
|
|
{
|
|
key: 'reassign',
|
|
header: texts.routeSteps.columnReassign,
|
|
align: 'center',
|
|
render: r => (r.allowReassignToOtherApprovers ? <Badge variant="ok">{texts.routeSteps.reassignAllowed}</Badge> : <Badge variant="neutral">{texts.common.no}</Badge>)
|
|
},
|
|
{
|
|
key: 'actions',
|
|
header: '',
|
|
width: '100px',
|
|
align: 'right',
|
|
sticky: true,
|
|
render: r => (
|
|
<ActionsCell>
|
|
<IconButton icon="edit" label={texts.common.edit} onClick={() => openEdit(r)} />
|
|
<IconButton icon="trash" label={texts.common.remove} danger onClick={() => deleteTarget.ask(r)} />
|
|
</ActionsCell>
|
|
)
|
|
}
|
|
]}
|
|
rows={steps.items}
|
|
keyOf={r => r.id}
|
|
emptyMessage={steps.isLoading ? texts.common.loading : texts.routeSteps.emptyList}
|
|
/>
|
|
|
|
{showForm && (
|
|
<RouteStepFormModal
|
|
api={api}
|
|
route={route}
|
|
editing={editing}
|
|
nextOrderNo={nextOrderNo}
|
|
onSaved={handleSaved}
|
|
onClose={() => setShowForm(false)}
|
|
/>
|
|
)}
|
|
|
|
{deleteTarget.target && (
|
|
<ConfirmDialog
|
|
title={texts.routeSteps.deleteTitle}
|
|
text={texts.routeSteps.deleteText(deleteTarget.target.orderNo)}
|
|
confirmLabel={texts.common.remove}
|
|
busy={deleteTarget.isBusy}
|
|
onCancel={deleteTarget.cancel}
|
|
onConfirm={deleteTarget.confirm}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|