Claude güncellemesi Workflow Reset güncellemesi
This commit is contained in:
parent
db24baed91
commit
1fe4abaeb6
13 changed files with 304 additions and 2 deletions
|
|
@ -9,6 +9,7 @@ public class WorkflowDto
|
|||
public string ApprovalStatusFieldName { get; set; }
|
||||
public string ApprovalDescriptionFieldName { get; set; }
|
||||
public bool ApprovalIsFilterUserName { get; set; }
|
||||
public bool ApprovalIsResetWorkflow { get; set; }
|
||||
|
||||
public List<ListFormWorkflowCriteriaDto> Criteria { get; set; } = [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,5 +11,6 @@ public interface IListFormWorkflowAppService : IApplicationService
|
|||
Task DeleteCriteriaAsync(string id);
|
||||
Task<ListFormWorkflowStateDto> ResetDemoAsync(string listFormCode = null);
|
||||
Task<WorkflowRunResultDto> StartAsync(StartWorkflowDto input);
|
||||
Task<WorkflowRunResultDto> ResetAsync(StartWorkflowDto input);
|
||||
Task<WorkflowRunResultDto> DecisionAsync(DecisionWorkflowDto input);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -318,6 +318,65 @@ public class ListFormWorkflowAppService : PlatformAppService, IListFormWorkflowA
|
|||
return result;
|
||||
}
|
||||
|
||||
[HttpPost("reset")]
|
||||
public async Task<WorkflowRunResultDto> ResetAsync(StartWorkflowDto input)
|
||||
{
|
||||
if (input.Keys?.Length > 1)
|
||||
{
|
||||
return await RunForEachKeyAsync(input.Keys, keys => ResetSingleAsync(input.ListFormCode, keys));
|
||||
}
|
||||
|
||||
return await ResetSingleAsync(input.ListFormCode, input.Keys);
|
||||
}
|
||||
|
||||
private async Task<WorkflowRunResultDto> ResetSingleAsync(string listFormCode, object[] keys)
|
||||
{
|
||||
var context = await CreateRunContextAsync(listFormCode, keys);
|
||||
if (!context.Workflow.ApprovalIsResetWorkflow)
|
||||
{
|
||||
throw new UserFriendlyException("Bu liste formu için workflow sıfırlama tanımlı değil.");
|
||||
}
|
||||
|
||||
var start = context.Criteria.FirstOrDefault(x => x.Kind == "Start")
|
||||
?? throw new UserFriendlyException("Workflow başlangıç adımı bulunamadı.");
|
||||
|
||||
var previousStatus = GetRowValue(context.Row, context.Workflow.ApprovalStatusFieldName)?.ToString();
|
||||
|
||||
var clear = new Dictionary<string, object>
|
||||
{
|
||||
[context.Workflow.ApprovalStatusFieldName] = null
|
||||
};
|
||||
if (!context.Workflow.ApprovalUserFieldName.IsNullOrWhiteSpace())
|
||||
{
|
||||
clear[context.Workflow.ApprovalUserFieldName] = null;
|
||||
}
|
||||
if (!context.Workflow.ApprovalDateFieldName.IsNullOrWhiteSpace())
|
||||
{
|
||||
clear[context.Workflow.ApprovalDateFieldName] = null;
|
||||
}
|
||||
if (!context.Workflow.ApprovalDescriptionFieldName.IsNullOrWhiteSpace())
|
||||
{
|
||||
clear[context.Workflow.ApprovalDescriptionFieldName] = null;
|
||||
}
|
||||
|
||||
await UpdateRowAsync(context, clear);
|
||||
MergeRowValues(context.Row, clear);
|
||||
|
||||
context.WorkflowNoteRows.Add(("Reset By: ", ResolveCurrentUserDisplayName()));
|
||||
if (!previousStatus.IsNullOrWhiteSpace())
|
||||
{
|
||||
context.WorkflowNoteRows.Add(("Reset Step: ", previousStatus));
|
||||
}
|
||||
|
||||
var result = await RunUntilWaitAsync(context, start);
|
||||
await InsertWorkflowNoteAsync(
|
||||
context,
|
||||
$"Workflow Reset: {start.Title}",
|
||||
BuildWorkflowNoteContent(context.WorkflowNoteRows));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[HttpPost("decision")]
|
||||
public async Task<WorkflowRunResultDto> DecisionAsync(DecisionWorkflowDto input)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3792,6 +3792,24 @@
|
|||
"en": "Workflow has already been started for the selected record",
|
||||
"tr": "Seçili kayıt icin workflow zaten başlamış."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListForm.WorkflowReset",
|
||||
"en": "Workflow Reset",
|
||||
"tr": "İş Akışı Sıfırla"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListForm.WorkflowResetMessage",
|
||||
"en": "All approvals of the selected {0} record(s) will be removed and the workflow will start over. Do you confirm?",
|
||||
"tr": "Seçili {0} kaydın tüm onayları kaldırılacak ve iş akışı baştan başlatılacak. Onaylıyor musunuz?"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListForm.WorkflowNotStarted",
|
||||
"en": "Workflow has not been started for the selected record",
|
||||
"tr": "Seçili kayıt için workflow başlatılmamış."
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "SeciliKayitlarSilmekIstiyormusunuz",
|
||||
|
|
@ -20034,6 +20052,12 @@
|
|||
"en": "Filter User Name?",
|
||||
"tr": "Kullanıcı Adı Filtresin mi?"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.Workflow.ApprovalIsResetWorkflow",
|
||||
"en": "Workflow Reset?",
|
||||
"tr": "İş Akışı Sıfırlama?"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.Workflow.ApprovalDescriptionFieldName",
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ public class Workflow : ValueObject
|
|||
public string ApprovalStatusFieldName { get; set; }
|
||||
public string ApprovalDescriptionFieldName { get; set; }
|
||||
public bool ApprovalIsFilterUserName { get; set; }
|
||||
public bool ApprovalIsResetWorkflow { get; set; }
|
||||
|
||||
protected override IEnumerable<object> GetAtomicValues()
|
||||
{
|
||||
|
|
@ -18,6 +19,7 @@ public class Workflow : ValueObject
|
|||
yield return ApprovalStatusFieldName;
|
||||
yield return ApprovalDescriptionFieldName;
|
||||
yield return ApprovalIsFilterUserName;
|
||||
yield return ApprovalIsResetWorkflow;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -930,6 +930,7 @@ export interface WorkflowDto {
|
|||
approvalStatusFieldName: string
|
||||
approvalDescriptionFieldName: string
|
||||
approvalIsFilterUserName: boolean
|
||||
approvalIsResetWorkflow: boolean
|
||||
criteria: ListFormWorkflowCriteriaDto[]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,6 +101,16 @@ export const workflowService = {
|
|||
return response.data
|
||||
},
|
||||
|
||||
async resetWorkflow(listFormCode: string, keys: unknown[]) {
|
||||
const response = await apiService.fetchData<WorkflowRunResultDto>({
|
||||
method: 'POST',
|
||||
url: `${baseUrl}/reset`,
|
||||
data: { listFormCode, keys },
|
||||
})
|
||||
|
||||
return response.data
|
||||
},
|
||||
|
||||
async decideWorkflow(
|
||||
listFormCode: string,
|
||||
keys: unknown[],
|
||||
|
|
|
|||
|
|
@ -318,6 +318,7 @@ export function FormTabWorkflow(
|
|||
approvalDateFieldName: string(),
|
||||
approvalDescriptionFieldName: string(),
|
||||
approvalIsFilterUserName: bool(),
|
||||
approvalIsResetWorkflow: bool(),
|
||||
}),
|
||||
})
|
||||
|
||||
|
|
@ -340,7 +341,7 @@ export function FormTabWorkflow(
|
|||
<Form>
|
||||
<FormContainer size="sm">
|
||||
<Card className="my-2">
|
||||
<div className="grid grid-cols-1 md:grid-cols-5 gap-2">
|
||||
<div className="grid grid-cols-1 md:grid-cols-6 gap-2">
|
||||
<FormItem
|
||||
asterisk
|
||||
label={translate('::ListForms.ListFormEdit.Workflow.ApprovalUserFieldName')}
|
||||
|
|
@ -454,6 +455,19 @@ export function FormTabWorkflow(
|
|||
>
|
||||
<Field name="workflowDto.approvalIsFilterUserName" component={Checkbox} />
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.Workflow.ApprovalIsResetWorkflow')}
|
||||
invalid={
|
||||
!!(
|
||||
errors.workflowDto?.approvalIsResetWorkflow &&
|
||||
touched.workflowDto?.approvalIsResetWorkflow
|
||||
)
|
||||
}
|
||||
errorMessage={errors.workflowDto?.approvalIsResetWorkflow as string}
|
||||
>
|
||||
<Field name="workflowDto.approvalIsResetWorkflow" component={Checkbox} />
|
||||
</FormItem>
|
||||
</div>
|
||||
|
||||
<Button block size="sm" variant="solid" type="submit" loading={isSubmitting}>
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ const initialValues: ListFormWizardDto = {
|
|||
approvalStatusFieldName: '',
|
||||
approvalDescriptionFieldName: '',
|
||||
approvalIsFilterUserName: false,
|
||||
approvalIsResetWorkflow: false,
|
||||
criteria: [],
|
||||
},
|
||||
languageTextMenuEn: '',
|
||||
|
|
@ -369,6 +370,7 @@ const Wizard = () => {
|
|||
approvalStatusFieldName: '',
|
||||
approvalDescriptionFieldName: '',
|
||||
approvalIsFilterUserName: false,
|
||||
approvalIsResetWorkflow: false,
|
||||
criteria: [],
|
||||
})
|
||||
const [criteria, setCriteria] = useState<ListFormWorkflowCriteriaDto[]>([])
|
||||
|
|
|
|||
|
|
@ -558,6 +558,10 @@ const WizardStep11 = ({
|
|||
label="Is Filter User Name?"
|
||||
value={workflow.approvalIsFilterUserName === true ? 'Yes' : 'No'}
|
||||
/>
|
||||
<Row
|
||||
label="Is Reset Workflow?"
|
||||
value={workflow.approvalIsResetWorkflow === true ? 'Yes' : 'No'}
|
||||
/>
|
||||
</div>
|
||||
{workflowItems.length > 0 && (
|
||||
<div className="flex flex-col gap-2">
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ function WizardStep6({
|
|||
<Form>
|
||||
<Card className="mb-4" header={translate('::ListForms.ListFormEdit.TabWorkflow')}>
|
||||
<FormContainer>
|
||||
<div className="grid grid-cols-1 md:grid-cols-5 gap-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-6 gap-4">
|
||||
{[
|
||||
[
|
||||
'approvalUserFieldName',
|
||||
|
|
@ -381,6 +381,26 @@ function WizardStep6({
|
|||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.Workflow.ApprovalIsResetWorkflow')}
|
||||
>
|
||||
<Field name="approvalIsResetWorkflow">
|
||||
{({ field, form }: FieldProps<boolean>) => (
|
||||
<Checkbox
|
||||
name={field.name}
|
||||
checked={Boolean(values.approvalIsResetWorkflow)}
|
||||
onChange={(checked) => {
|
||||
form.setFieldValue(field.name, checked)
|
||||
onWorkflowChange({
|
||||
...values,
|
||||
approvalIsResetWorkflow: checked,
|
||||
criteria,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</FormItem>
|
||||
</div>
|
||||
</FormContainer>
|
||||
</Card>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ const orderedToolbarItemNames = [
|
|||
'addRowButton',
|
||||
'refreshButton',
|
||||
'openDynamicGridReport',
|
||||
'workflowReset',
|
||||
'workflowStart',
|
||||
'expandAllButton',
|
||||
'collapseAllButton',
|
||||
|
|
|
|||
|
|
@ -154,6 +154,85 @@ const useToolbar = ({
|
|||
approvalCriteria.length > 0 &&
|
||||
grdOpt.updateServiceAddress
|
||||
) {
|
||||
if (workflowOptions.approvalIsResetWorkflow) {
|
||||
items.push({
|
||||
widget: 'dxButton',
|
||||
name: 'workflowReset',
|
||||
location: 'after',
|
||||
locateInMenu: 'auto',
|
||||
showText: 'always',
|
||||
options: {
|
||||
icon: 'revert',
|
||||
text: toToolbarText(translate('::ListForms.ListForm.WorkflowReset')),
|
||||
hint: translate('::ListForms.ListForm.WorkflowReset'),
|
||||
visible: true,
|
||||
disabled: true,
|
||||
onClick: async () => {
|
||||
const selectedRowKeys = (await Promise.resolve(
|
||||
getSelectedRowKeys() as any,
|
||||
)) as unknown[]
|
||||
if (!selectedRowKeys?.length) {
|
||||
toast.push(
|
||||
<Notification type="warning" duration={2000}>
|
||||
{translate('::ListForms.ListForm.SelectRecord')}
|
||||
</Notification>,
|
||||
{ placement: 'bottom-end' },
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
const selectedRows = ((await Promise.resolve(getSelectedRowsData() as any)) ||
|
||||
[]) as Record<string, unknown>[]
|
||||
if (
|
||||
selectedRows.length === 0 ||
|
||||
selectedRows.some((row) => isWorkflowNotStarted(row, workflowOptions))
|
||||
) {
|
||||
toast.push(
|
||||
<Notification type="warning" duration={2500}>
|
||||
{translate('::ListForms.ListForm.WorkflowNotStarted')}
|
||||
</Notification>,
|
||||
{ placement: 'bottom-end' },
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
!grdOpt.keyFieldName ||
|
||||
selectedRows.some(
|
||||
(row) =>
|
||||
row[grdOpt.keyFieldName!] === undefined || row[grdOpt.keyFieldName!] === null,
|
||||
)
|
||||
) {
|
||||
toast.push(
|
||||
<Notification type="danger" duration={3000}>
|
||||
Liste formu anahtar alanı seçili kayıtlarda bulunamadı.
|
||||
</Notification>,
|
||||
{ placement: 'bottom-end' },
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
const keys = selectedRows.map((row) => row[grdOpt.keyFieldName!])
|
||||
|
||||
setToolbarModalData({
|
||||
open: true,
|
||||
content: (
|
||||
<WorkflowResetConfirmDialog
|
||||
keys={keys}
|
||||
listFormCode={listFormCode}
|
||||
onCancel={() => setToolbarModalData(undefined)}
|
||||
onCompleted={() => {
|
||||
refreshData()
|
||||
setToolbarModalData(undefined)
|
||||
}}
|
||||
/>
|
||||
),
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
items.push({
|
||||
widget: 'dxButton',
|
||||
name: 'workflowStart',
|
||||
|
|
@ -716,6 +795,14 @@ export function isWorkflowToolbarItemDisabled(
|
|||
)
|
||||
}
|
||||
|
||||
if (itemName === 'workflowReset') {
|
||||
return (
|
||||
!workflowOptions.approvalIsResetWorkflow ||
|
||||
selectedRowsData.length === 0 ||
|
||||
selectedRowsData.some((row) => isWorkflowNotStarted(row, workflowOptions))
|
||||
)
|
||||
}
|
||||
|
||||
if (!itemName.startsWith('workflowApproval_')) {
|
||||
return undefined
|
||||
}
|
||||
|
|
@ -778,6 +865,22 @@ export function updateWorkflowApprovalToolbarItems(
|
|||
}
|
||||
}
|
||||
|
||||
const workflowResetItemIndex = toolbarOptions.items
|
||||
.map((item: any) => item.name)
|
||||
.indexOf('workflowReset')
|
||||
|
||||
if (workflowResetItemIndex >= 0) {
|
||||
const resetEnabled =
|
||||
workflowOptions.approvalIsResetWorkflow === true &&
|
||||
selectedRowsData.length > 0 &&
|
||||
selectedRowsData.every((row) => !isWorkflowNotStarted(row, workflowOptions))
|
||||
const resetOptionPath = `toolbar.items[${workflowResetItemIndex}].options.disabled`
|
||||
const nextResetDisabled = !resetEnabled
|
||||
if (component.option(resetOptionPath) !== nextResetDisabled) {
|
||||
component.option(resetOptionPath, nextResetDisabled)
|
||||
}
|
||||
}
|
||||
|
||||
const currentUserIdentities = getCurrentUserWorkflowIdentities(currentUser)
|
||||
|
||||
approvalCriteria.forEach((criteria) => {
|
||||
|
|
@ -808,6 +911,66 @@ export function updateWorkflowApprovalToolbarItems(
|
|||
})
|
||||
}
|
||||
|
||||
function WorkflowResetConfirmDialog({
|
||||
keys,
|
||||
listFormCode,
|
||||
onCancel,
|
||||
onCompleted,
|
||||
}: {
|
||||
keys: unknown[]
|
||||
listFormCode: string
|
||||
onCancel: () => void
|
||||
onCompleted: () => void
|
||||
}) {
|
||||
const { translate } = useLocalization()
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
|
||||
const reset = async () => {
|
||||
setSubmitting(true)
|
||||
try {
|
||||
const results = await Promise.all(
|
||||
keys.map((key) => workflowService.resetWorkflow(listFormCode, [key])),
|
||||
)
|
||||
showWorkflowToastMessages(results)
|
||||
onCompleted()
|
||||
} catch (error: any) {
|
||||
toast.push(
|
||||
<Notification type="danger" duration={3000}>
|
||||
{error?.response?.data?.error?.message ||
|
||||
error?.response?.data?.message ||
|
||||
error?.message ||
|
||||
'Workflow sifirlanamadi.'}
|
||||
</Notification>,
|
||||
{ placement: 'bottom-end' },
|
||||
)
|
||||
} finally {
|
||||
setSubmitting(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h5 className="mb-4">{translate('::ListForms.ListForm.WorkflowReset')}</h5>
|
||||
<p className="mb-4">
|
||||
{translate('::ListForms.ListForm.WorkflowResetMessage', { 0: keys.length })}
|
||||
</p>
|
||||
<div className="text-right mt-6">
|
||||
<Button
|
||||
className="ltr:mr-2 rtl:ml-2"
|
||||
variant="plain"
|
||||
disabled={submitting}
|
||||
onClick={onCancel}
|
||||
>
|
||||
{translate('::Cancel')}
|
||||
</Button>
|
||||
<Button variant="solid" disabled={submitting} onClick={reset}>
|
||||
{translate('::ListForms.ListForm.WorkflowReset')}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function WorkflowApprovalDecisionDialog({
|
||||
criteriaTitle,
|
||||
keys,
|
||||
|
|
|
|||
Loading…
Reference in a new issue