Merge branch 'main' into feature/remove-loop-reset
This commit is contained in:
commit
2ecfecb9b4
|
@ -660,6 +660,18 @@ paths:
|
||||||
description: The username of the process initiator
|
description: The username of the process initiator
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
- name: report_columns
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Base64 encoded json of report columns.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: report_filter_by
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Base64 encoded json of report filter by.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
get:
|
get:
|
||||||
operationId: spiffworkflow_backend.routes.process_instances_controller.process_instance_list_for_me
|
operationId: spiffworkflow_backend.routes.process_instances_controller.process_instance_list_for_me
|
||||||
summary: Returns a list of process instances that are associated with me.
|
summary: Returns a list of process instances that are associated with me.
|
||||||
|
@ -779,6 +791,18 @@ paths:
|
||||||
description: The username of the process initiator
|
description: The username of the process initiator
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
- name: report_columns
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Base64 encoded json of report columns.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: report_filter_by
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
description: Base64 encoded json of report filter by.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
get:
|
get:
|
||||||
operationId: spiffworkflow_backend.routes.process_instances_controller.process_instance_list
|
operationId: spiffworkflow_backend.routes.process_instances_controller.process_instance_list
|
||||||
summary: Returns a list of process instances.
|
summary: Returns a list of process instances.
|
||||||
|
|
|
@ -55,7 +55,7 @@ class TaskModel(SpiffworkflowBaseDBModel):
|
||||||
json_data_hash: str = db.Column(db.String(255), nullable=False, index=True)
|
json_data_hash: str = db.Column(db.String(255), nullable=False, index=True)
|
||||||
|
|
||||||
start_in_seconds: float = db.Column(db.DECIMAL(17, 6))
|
start_in_seconds: float = db.Column(db.DECIMAL(17, 6))
|
||||||
end_in_seconds: float | None = db.Column(db.DECIMAL(17, 6))
|
end_in_seconds: Union[float, None] = db.Column(db.DECIMAL(17, 6))
|
||||||
|
|
||||||
|
|
||||||
class Task:
|
class Task:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""APIs for dealing with process groups, process models, and process instances."""
|
"""APIs for dealing with process groups, process models, and process instances."""
|
||||||
|
import base64
|
||||||
import json
|
import json
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
@ -117,10 +118,10 @@ def process_instance_run(
|
||||||
)
|
)
|
||||||
|
|
||||||
processor = ProcessInstanceProcessor(process_instance)
|
processor = ProcessInstanceProcessor(process_instance)
|
||||||
processor.lock_process_instance("Web")
|
|
||||||
|
|
||||||
if do_engine_steps:
|
if do_engine_steps:
|
||||||
try:
|
try:
|
||||||
|
processor.lock_process_instance("Web")
|
||||||
processor.do_engine_steps(save=True)
|
processor.do_engine_steps(save=True)
|
||||||
except ApiError as e:
|
except ApiError as e:
|
||||||
ErrorHandlingService().handle_error(processor, e)
|
ErrorHandlingService().handle_error(processor, e)
|
||||||
|
@ -252,6 +253,8 @@ def process_instance_list_for_me(
|
||||||
report_id: Optional[int] = None,
|
report_id: Optional[int] = None,
|
||||||
user_group_identifier: Optional[str] = None,
|
user_group_identifier: Optional[str] = None,
|
||||||
process_initiator_username: Optional[str] = None,
|
process_initiator_username: Optional[str] = None,
|
||||||
|
report_columns: Optional[str] = None,
|
||||||
|
report_filter_by: Optional[str] = None,
|
||||||
) -> flask.wrappers.Response:
|
) -> flask.wrappers.Response:
|
||||||
"""Process_instance_list_for_me."""
|
"""Process_instance_list_for_me."""
|
||||||
return process_instance_list(
|
return process_instance_list(
|
||||||
|
@ -268,6 +271,8 @@ def process_instance_list_for_me(
|
||||||
report_id=report_id,
|
report_id=report_id,
|
||||||
user_group_identifier=user_group_identifier,
|
user_group_identifier=user_group_identifier,
|
||||||
with_relation_to_me=True,
|
with_relation_to_me=True,
|
||||||
|
report_columns=report_columns,
|
||||||
|
report_filter_by=report_filter_by,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -286,12 +291,21 @@ def process_instance_list(
|
||||||
report_id: Optional[int] = None,
|
report_id: Optional[int] = None,
|
||||||
user_group_identifier: Optional[str] = None,
|
user_group_identifier: Optional[str] = None,
|
||||||
process_initiator_username: Optional[str] = None,
|
process_initiator_username: Optional[str] = None,
|
||||||
|
report_columns: Optional[str] = None,
|
||||||
|
report_filter_by: Optional[str] = None,
|
||||||
) -> flask.wrappers.Response:
|
) -> flask.wrappers.Response:
|
||||||
"""Process_instance_list."""
|
"""Process_instance_list."""
|
||||||
process_instance_report = ProcessInstanceReportService.report_with_identifier(
|
process_instance_report = ProcessInstanceReportService.report_with_identifier(
|
||||||
g.user, report_id, report_identifier
|
g.user, report_id, report_identifier
|
||||||
)
|
)
|
||||||
|
|
||||||
|
report_column_list = None
|
||||||
|
if report_columns:
|
||||||
|
report_column_list = json.loads(base64.b64decode(report_columns))
|
||||||
|
report_filter_by_list = None
|
||||||
|
if report_filter_by:
|
||||||
|
report_filter_by_list = json.loads(base64.b64decode(report_filter_by))
|
||||||
|
|
||||||
if user_filter:
|
if user_filter:
|
||||||
report_filter = ProcessInstanceReportFilter(
|
report_filter = ProcessInstanceReportFilter(
|
||||||
process_model_identifier=process_model_identifier,
|
process_model_identifier=process_model_identifier,
|
||||||
|
@ -303,6 +317,8 @@ def process_instance_list(
|
||||||
with_relation_to_me=with_relation_to_me,
|
with_relation_to_me=with_relation_to_me,
|
||||||
process_status=process_status.split(",") if process_status else None,
|
process_status=process_status.split(",") if process_status else None,
|
||||||
process_initiator_username=process_initiator_username,
|
process_initiator_username=process_initiator_username,
|
||||||
|
report_column_list=report_column_list,
|
||||||
|
report_filter_by_list=report_filter_by_list,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
report_filter = (
|
report_filter = (
|
||||||
|
@ -317,6 +333,8 @@ def process_instance_list(
|
||||||
process_status=process_status,
|
process_status=process_status,
|
||||||
with_relation_to_me=with_relation_to_me,
|
with_relation_to_me=with_relation_to_me,
|
||||||
process_initiator_username=process_initiator_username,
|
process_initiator_username=process_initiator_username,
|
||||||
|
report_column_list=report_column_list,
|
||||||
|
report_filter_by_list=report_filter_by_list,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
import sys
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
@ -171,6 +172,10 @@ def setup_logger(app: Flask) -> None:
|
||||||
the_logger.propagate = False
|
the_logger.propagate = False
|
||||||
the_logger.addHandler(spiff_logger_filehandler)
|
the_logger.addHandler(spiff_logger_filehandler)
|
||||||
else:
|
else:
|
||||||
|
if len(the_logger.handlers) < 1:
|
||||||
|
# it's very verbose, so only add handlers for the obscure loggers when log level is DEBUG
|
||||||
|
if upper_log_level_string == "DEBUG":
|
||||||
|
the_logger.addHandler(logging.StreamHandler(sys.stdout))
|
||||||
for the_handler in the_logger.handlers:
|
for the_handler in the_logger.handlers:
|
||||||
the_handler.setFormatter(log_formatter)
|
the_handler.setFormatter(log_formatter)
|
||||||
the_handler.setLevel(log_level)
|
the_handler.setLevel(log_level)
|
||||||
|
|
|
@ -50,6 +50,8 @@ class ProcessInstanceReportFilter:
|
||||||
with_tasks_assigned_to_my_group: Optional[bool] = None
|
with_tasks_assigned_to_my_group: Optional[bool] = None
|
||||||
with_relation_to_me: Optional[bool] = None
|
with_relation_to_me: Optional[bool] = None
|
||||||
process_initiator_username: Optional[str] = None
|
process_initiator_username: Optional[str] = None
|
||||||
|
report_column_list: Optional[list] = None
|
||||||
|
report_filter_by_list: Optional[list] = None
|
||||||
|
|
||||||
def to_dict(self) -> dict[str, str]:
|
def to_dict(self) -> dict[str, str]:
|
||||||
"""To_dict."""
|
"""To_dict."""
|
||||||
|
@ -85,6 +87,10 @@ class ProcessInstanceReportFilter:
|
||||||
d["with_relation_to_me"] = str(self.with_relation_to_me).lower()
|
d["with_relation_to_me"] = str(self.with_relation_to_me).lower()
|
||||||
if self.process_initiator_username is not None:
|
if self.process_initiator_username is not None:
|
||||||
d["process_initiator_username"] = str(self.process_initiator_username)
|
d["process_initiator_username"] = str(self.process_initiator_username)
|
||||||
|
if self.report_column_list is not None:
|
||||||
|
d["report_column_list"] = str(self.report_column_list)
|
||||||
|
if self.report_filter_by_list is not None:
|
||||||
|
d["report_filter_by_list"] = str(self.report_filter_by_list)
|
||||||
|
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
@ -229,6 +235,8 @@ class ProcessInstanceReportService:
|
||||||
with_tasks_assigned_to_my_group = bool_value("with_tasks_assigned_to_my_group")
|
with_tasks_assigned_to_my_group = bool_value("with_tasks_assigned_to_my_group")
|
||||||
with_relation_to_me = bool_value("with_relation_to_me")
|
with_relation_to_me = bool_value("with_relation_to_me")
|
||||||
process_initiator_username = filters.get("process_initiator_username")
|
process_initiator_username = filters.get("process_initiator_username")
|
||||||
|
report_column_list = list_value("report_column_list")
|
||||||
|
report_filter_by_list = list_value("report_filter_by_list")
|
||||||
|
|
||||||
report_filter = ProcessInstanceReportFilter(
|
report_filter = ProcessInstanceReportFilter(
|
||||||
process_model_identifier=process_model_identifier,
|
process_model_identifier=process_model_identifier,
|
||||||
|
@ -244,6 +252,8 @@ class ProcessInstanceReportService:
|
||||||
with_tasks_assigned_to_my_group=with_tasks_assigned_to_my_group,
|
with_tasks_assigned_to_my_group=with_tasks_assigned_to_my_group,
|
||||||
with_relation_to_me=with_relation_to_me,
|
with_relation_to_me=with_relation_to_me,
|
||||||
process_initiator_username=process_initiator_username,
|
process_initiator_username=process_initiator_username,
|
||||||
|
report_column_list=report_column_list,
|
||||||
|
report_filter_by_list=report_filter_by_list,
|
||||||
)
|
)
|
||||||
|
|
||||||
return report_filter
|
return report_filter
|
||||||
|
@ -265,6 +275,8 @@ class ProcessInstanceReportService:
|
||||||
with_tasks_assigned_to_my_group: Optional[bool] = None,
|
with_tasks_assigned_to_my_group: Optional[bool] = None,
|
||||||
with_relation_to_me: Optional[bool] = None,
|
with_relation_to_me: Optional[bool] = None,
|
||||||
process_initiator_username: Optional[str] = None,
|
process_initiator_username: Optional[str] = None,
|
||||||
|
report_column_list: Optional[list] = None,
|
||||||
|
report_filter_by_list: Optional[list] = None,
|
||||||
) -> ProcessInstanceReportFilter:
|
) -> ProcessInstanceReportFilter:
|
||||||
"""Filter_from_metadata_with_overrides."""
|
"""Filter_from_metadata_with_overrides."""
|
||||||
report_filter = cls.filter_from_metadata(process_instance_report)
|
report_filter = cls.filter_from_metadata(process_instance_report)
|
||||||
|
@ -291,6 +303,10 @@ class ProcessInstanceReportService:
|
||||||
report_filter.with_tasks_completed_by_me = with_tasks_completed_by_me
|
report_filter.with_tasks_completed_by_me = with_tasks_completed_by_me
|
||||||
if process_initiator_username is not None:
|
if process_initiator_username is not None:
|
||||||
report_filter.process_initiator_username = process_initiator_username
|
report_filter.process_initiator_username = process_initiator_username
|
||||||
|
if report_column_list is not None:
|
||||||
|
report_filter.report_column_list = report_column_list
|
||||||
|
if report_filter_by_list is not None:
|
||||||
|
report_filter.report_filter_by_list = report_filter_by_list
|
||||||
if with_tasks_assigned_to_my_group is not None:
|
if with_tasks_assigned_to_my_group is not None:
|
||||||
report_filter.with_tasks_assigned_to_my_group = (
|
report_filter.with_tasks_assigned_to_my_group = (
|
||||||
with_tasks_assigned_to_my_group
|
with_tasks_assigned_to_my_group
|
||||||
|
@ -483,6 +499,15 @@ class ProcessInstanceReportService:
|
||||||
stock_columns = ProcessInstanceReportService.get_column_names_for_model(
|
stock_columns = ProcessInstanceReportService.get_column_names_for_model(
|
||||||
ProcessInstanceModel
|
ProcessInstanceModel
|
||||||
)
|
)
|
||||||
|
if report_filter.report_column_list:
|
||||||
|
process_instance_report.report_metadata["columns"] = (
|
||||||
|
report_filter.report_column_list
|
||||||
|
)
|
||||||
|
if report_filter.report_filter_by_list:
|
||||||
|
process_instance_report.report_metadata["filter_by"] = (
|
||||||
|
report_filter.report_filter_by_list
|
||||||
|
)
|
||||||
|
|
||||||
for column in process_instance_report.report_metadata["columns"]:
|
for column in process_instance_report.report_metadata["columns"]:
|
||||||
if column["accessor"] in stock_columns:
|
if column["accessor"] in stock_columns:
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -10,7 +10,7 @@ const approveWithUser = (
|
||||||
.contains(/^Submit$/)
|
.contains(/^Submit$/)
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
cy.contains('Tasks I can complete', { timeout: 20000 });
|
cy.contains('Tasks I can complete', { timeout: 30000 });
|
||||||
cy.get('.cds--btn').contains(/^Go$/).click();
|
cy.get('.cds--btn').contains(/^Go$/).click();
|
||||||
|
|
||||||
// approve!
|
// approve!
|
||||||
|
@ -19,12 +19,12 @@ const approveWithUser = (
|
||||||
.contains(/^Submit$/)
|
.contains(/^Submit$/)
|
||||||
.click();
|
.click();
|
||||||
if (expectAdditionalApprovalInfoPage) {
|
if (expectAdditionalApprovalInfoPage) {
|
||||||
cy.contains(expectAdditionalApprovalInfoPage, { timeout: 20000 });
|
cy.contains(expectAdditionalApprovalInfoPage, { timeout: 30000 });
|
||||||
cy.get('button')
|
cy.get('button')
|
||||||
.contains(/^Continue$/)
|
.contains(/^Continue$/)
|
||||||
.click();
|
.click();
|
||||||
}
|
}
|
||||||
cy.location({ timeout: 20000 }).should((loc) => {
|
cy.location({ timeout: 30000 }).should((loc) => {
|
||||||
expect(loc.pathname).to.eq('/tasks');
|
expect(loc.pathname).to.eq('/tasks');
|
||||||
});
|
});
|
||||||
cy.logout();
|
cy.logout();
|
||||||
|
@ -37,7 +37,7 @@ describe('pp1', () => {
|
||||||
cy.contains('Start New +').click();
|
cy.contains('Start New +').click();
|
||||||
cy.contains('Raise New Demand Request');
|
cy.contains('Raise New Demand Request');
|
||||||
cy.runPrimaryBpmnFile(true);
|
cy.runPrimaryBpmnFile(true);
|
||||||
cy.contains('Please select the type of request to Start the process.');
|
cy.contains('Please select the type of request to start the process.');
|
||||||
// wait a second to ensure we can click the radio button
|
// wait a second to ensure we can click the radio button
|
||||||
cy.wait(1000);
|
cy.wait(1000);
|
||||||
cy.get('input#root-procurement').click();
|
cy.get('input#root-procurement').click();
|
||||||
|
@ -47,7 +47,7 @@ describe('pp1', () => {
|
||||||
.click();
|
.click();
|
||||||
cy.contains(
|
cy.contains(
|
||||||
'Submit a new demand request for the procurement of needed items',
|
'Submit a new demand request for the procurement of needed items',
|
||||||
{ timeout: 20000 }
|
{ timeout: 30000 }
|
||||||
);
|
);
|
||||||
|
|
||||||
cy.url().then((currentUrl) => {
|
cy.url().then((currentUrl) => {
|
||||||
|
@ -68,7 +68,7 @@ describe('pp1', () => {
|
||||||
.contains(/^Submit$/)
|
.contains(/^Submit$/)
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
cy.contains('Task: Enter NDR Items', { timeout: 20000 });
|
cy.contains('Task: Enter NDR Items', { timeout: 30000 });
|
||||||
cy.get('#root_0_sub_category').select('op_src');
|
cy.get('#root_0_sub_category').select('op_src');
|
||||||
cy.get('#root_0_item').clear().type('spiffworkflow');
|
cy.get('#root_0_item').clear().type('spiffworkflow');
|
||||||
cy.get('#root_0_qty').clear().type('1');
|
cy.get('#root_0_qty').clear().type('1');
|
||||||
|
@ -81,13 +81,14 @@ describe('pp1', () => {
|
||||||
|
|
||||||
cy.contains(
|
cy.contains(
|
||||||
'Review and provide any supporting information or files for your request.',
|
'Review and provide any supporting information or files for your request.',
|
||||||
{ timeout: 20000 }
|
{ timeout: 30000 }
|
||||||
);
|
);
|
||||||
cy.contains('Submit the Request').click();
|
cy.contains('Submit the Request').click();
|
||||||
cy.get('input[value="Submit the Request"]').click();
|
cy.get('input[value="Submit the Request"]').click();
|
||||||
cy.get('button')
|
cy.get('button')
|
||||||
.contains(/^Submit$/)
|
.contains(/^Submit$/)
|
||||||
.click();
|
.click();
|
||||||
|
cy.contains('Tasks for my open instances', { timeout: 30000 });
|
||||||
|
|
||||||
cy.logout();
|
cy.logout();
|
||||||
approveWithUser(
|
approveWithUser(
|
||||||
|
|
|
@ -36,6 +36,7 @@ import {
|
||||||
convertSecondsToFormattedDateString,
|
convertSecondsToFormattedDateString,
|
||||||
convertSecondsToFormattedDateTime,
|
convertSecondsToFormattedDateTime,
|
||||||
convertSecondsToFormattedTimeHoursMinutes,
|
convertSecondsToFormattedTimeHoursMinutes,
|
||||||
|
encodeBase64,
|
||||||
getPageInfoFromSearchParams,
|
getPageInfoFromSearchParams,
|
||||||
getProcessModelFullIdentifierFromSearchParams,
|
getProcessModelFullIdentifierFromSearchParams,
|
||||||
modifyProcessIdentifierForPathParam,
|
modifyProcessIdentifierForPathParam,
|
||||||
|
@ -268,6 +269,17 @@ export default function ProcessInstanceListTable({
|
||||||
queryParamString += `&report_identifier=${reportIdentifier}`;
|
queryParamString += `&report_identifier=${reportIdentifier}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (searchParams.get('report_columns')) {
|
||||||
|
queryParamString += `&report_columns=${searchParams.get(
|
||||||
|
'report_columns'
|
||||||
|
)}`;
|
||||||
|
}
|
||||||
|
if (searchParams.get('report_filter_by')) {
|
||||||
|
queryParamString += `&report_filter_by=${searchParams.get(
|
||||||
|
'report_filter_by'
|
||||||
|
)}`;
|
||||||
|
}
|
||||||
|
|
||||||
Object.keys(dateParametersToAlwaysFilterBy).forEach(
|
Object.keys(dateParametersToAlwaysFilterBy).forEach(
|
||||||
(paramName: string) => {
|
(paramName: string) => {
|
||||||
const dateFunctionToCall =
|
const dateFunctionToCall =
|
||||||
|
@ -529,6 +541,14 @@ export default function ProcessInstanceListTable({
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const reportColumns = () => {
|
||||||
|
return (reportMetadata as any).columns;
|
||||||
|
};
|
||||||
|
|
||||||
|
const reportFilterBy = () => {
|
||||||
|
return (reportMetadata as any).filter_by;
|
||||||
|
};
|
||||||
|
|
||||||
const applyFilter = (event: any) => {
|
const applyFilter = (event: any) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const { page, perPage } = getPageInfoFromSearchParams(
|
const { page, perPage } = getPageInfoFromSearchParams(
|
||||||
|
@ -578,6 +598,11 @@ export default function ProcessInstanceListTable({
|
||||||
queryParamString += `&process_initiator_username=${processInitiatorSelection.username}`;
|
queryParamString += `&process_initiator_username=${processInitiatorSelection.username}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const reportColumnsBase64 = encodeBase64(JSON.stringify(reportColumns()));
|
||||||
|
queryParamString += `&report_columns=${reportColumnsBase64}`;
|
||||||
|
const reportFilterByBase64 = encodeBase64(JSON.stringify(reportFilterBy()));
|
||||||
|
queryParamString += `&report_filter_by=${reportFilterByBase64}`;
|
||||||
|
|
||||||
removeError();
|
removeError();
|
||||||
setProcessInstanceReportJustSaved(null);
|
setProcessInstanceReportJustSaved(null);
|
||||||
setProcessInstanceFilters({});
|
setProcessInstanceFilters({});
|
||||||
|
@ -683,10 +708,6 @@ export default function ProcessInstanceListTable({
|
||||||
navigate(`${processInstanceListPathPrefix}${queryParamString}`);
|
navigate(`${processInstanceListPathPrefix}${queryParamString}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const reportColumns = () => {
|
|
||||||
return (reportMetadata as any).columns;
|
|
||||||
};
|
|
||||||
|
|
||||||
const reportColumnAccessors = () => {
|
const reportColumnAccessors = () => {
|
||||||
return reportColumns().map((reportColumn: ReportColumn) => {
|
return reportColumns().map((reportColumn: ReportColumn) => {
|
||||||
return reportColumn.accessor;
|
return reportColumn.accessor;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
|
import { Buffer } from 'buffer';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DATE_TIME_FORMAT,
|
DATE_TIME_FORMAT,
|
||||||
DATE_FORMAT,
|
DATE_FORMAT,
|
||||||
|
@ -260,3 +262,11 @@ export const getBpmnProcessIdentifiers = (rootBpmnElement: any) => {
|
||||||
export const isInteger = (str: string | number) => {
|
export const isInteger = (str: string | number) => {
|
||||||
return /^\d+$/.test(str.toString());
|
return /^\d+$/.test(str.toString());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const encodeBase64 = (data: string) => {
|
||||||
|
return Buffer.from(data).toString('base64');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const decodeBase64 = (data: string) => {
|
||||||
|
return Buffer.from(data, 'base64').toString('ascii');
|
||||||
|
};
|
||||||
|
|
|
@ -80,7 +80,6 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
||||||
const [eventPayload, setEventPayload] = useState<string>('{}');
|
const [eventPayload, setEventPayload] = useState<string>('{}');
|
||||||
const [eventTextEditorEnabled, setEventTextEditorEnabled] =
|
const [eventTextEditorEnabled, setEventTextEditorEnabled] =
|
||||||
useState<boolean>(false);
|
useState<boolean>(false);
|
||||||
const [displayDetails, setDisplayDetails] = useState<boolean>(false);
|
|
||||||
const [showProcessInstanceMetadata, setShowProcessInstanceMetadata] =
|
const [showProcessInstanceMetadata, setShowProcessInstanceMetadata] =
|
||||||
useState<boolean>(false);
|
useState<boolean>(false);
|
||||||
|
|
||||||
|
@ -304,92 +303,26 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const detailedViewElement = () => {
|
|
||||||
if (!processInstance) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (displayDetails) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Grid condensed fullWidth>
|
|
||||||
<Button
|
|
||||||
kind="ghost"
|
|
||||||
className="button-link"
|
|
||||||
onClick={() => setDisplayDetails(false)}
|
|
||||||
title="Hide Details"
|
|
||||||
>
|
|
||||||
« Hide Details
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
<Grid condensed fullWidth>
|
|
||||||
<Column sm={1} md={1} lg={2} className="grid-list-title">
|
|
||||||
Updated At:{' '}
|
|
||||||
</Column>
|
|
||||||
<Column sm={3} md={3} lg={3} className="grid-date">
|
|
||||||
{convertSecondsToFormattedDateTime(
|
|
||||||
processInstance.updated_at_in_seconds
|
|
||||||
)}
|
|
||||||
</Column>
|
|
||||||
</Grid>
|
|
||||||
<Grid condensed fullWidth>
|
|
||||||
<Column sm={1} md={1} lg={2} className="grid-list-title">
|
|
||||||
Created At:{' '}
|
|
||||||
</Column>
|
|
||||||
<Column sm={3} md={3} lg={3} className="grid-date">
|
|
||||||
{convertSecondsToFormattedDateTime(
|
|
||||||
processInstance.created_at_in_seconds
|
|
||||||
)}
|
|
||||||
</Column>
|
|
||||||
</Grid>
|
|
||||||
<Grid condensed fullWidth>
|
|
||||||
<Column sm={1} md={1} lg={2} className="grid-list-title">
|
|
||||||
Process model revision:{' '}
|
|
||||||
</Column>
|
|
||||||
<Column sm={3} md={3} lg={3} className="grid-date">
|
|
||||||
{processInstance.bpmn_version_control_identifier} (
|
|
||||||
{processInstance.bpmn_version_control_type})
|
|
||||||
</Column>
|
|
||||||
</Grid>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Grid condensed fullWidth>
|
|
||||||
<Button
|
|
||||||
kind="ghost"
|
|
||||||
className="button-link"
|
|
||||||
onClick={() => setDisplayDetails(true)}
|
|
||||||
title="Show Details"
|
|
||||||
>
|
|
||||||
View Details »
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getInfoTag = () => {
|
const getInfoTag = () => {
|
||||||
if (!processInstance) {
|
if (!processInstance) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const currentEndDate = convertSecondsToFormattedDateTime(
|
let lastUpdatedTimeLabel = 'Updated At';
|
||||||
processInstance.end_in_seconds || 0
|
let lastUpdatedTime = processInstance.updated_at_in_seconds;
|
||||||
);
|
if (processInstance.end_in_seconds) {
|
||||||
let currentEndDateTag;
|
lastUpdatedTimeLabel = 'Completed';
|
||||||
if (currentEndDate) {
|
lastUpdatedTime = processInstance.end_in_seconds;
|
||||||
currentEndDateTag = (
|
|
||||||
<Grid condensed fullWidth>
|
|
||||||
<Column sm={1} md={1} lg={2} className="grid-list-title">
|
|
||||||
Completed:{' '}
|
|
||||||
</Column>
|
|
||||||
<Column sm={3} md={3} lg={3} className="grid-date">
|
|
||||||
{convertSecondsToFormattedDateTime(
|
|
||||||
processInstance.end_in_seconds || 0
|
|
||||||
) || 'N/A'}
|
|
||||||
</Column>
|
|
||||||
</Grid>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
const lastUpdatedTimeTag = (
|
||||||
|
<Grid condensed fullWidth>
|
||||||
|
<Column sm={1} md={1} lg={2} className="grid-list-title">
|
||||||
|
{lastUpdatedTimeLabel}:{' '}
|
||||||
|
</Column>
|
||||||
|
<Column sm={3} md={3} lg={3} className="grid-date">
|
||||||
|
{convertSecondsToFormattedDateTime(lastUpdatedTime || 0) || 'N/A'}
|
||||||
|
</Column>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
|
||||||
let statusIcon = <InProgress />;
|
let statusIcon = <InProgress />;
|
||||||
if (processInstance.status === 'suspended') {
|
if (processInstance.status === 'suspended') {
|
||||||
|
@ -433,13 +366,30 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
||||||
<Column sm={1} md={1} lg={2} className="grid-list-title">
|
<Column sm={1} md={1} lg={2} className="grid-list-title">
|
||||||
Started:{' '}
|
Started:{' '}
|
||||||
</Column>
|
</Column>
|
||||||
<Column sm={3} md={3} lg={3} className="grid-date">
|
<Column
|
||||||
|
sm={3}
|
||||||
|
md={3}
|
||||||
|
lg={3}
|
||||||
|
className="grid-date"
|
||||||
|
title={`Created At: ${convertSecondsToFormattedDateTime(
|
||||||
|
processInstance.created_at_in_seconds
|
||||||
|
)}`}
|
||||||
|
>
|
||||||
{convertSecondsToFormattedDateTime(
|
{convertSecondsToFormattedDateTime(
|
||||||
processInstance.start_in_seconds || 0
|
processInstance.start_in_seconds || 0
|
||||||
)}
|
)}
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
{currentEndDateTag}
|
{lastUpdatedTimeTag}
|
||||||
|
<Grid condensed fullWidth>
|
||||||
|
<Column sm={1} md={1} lg={2} className="grid-list-title">
|
||||||
|
Process model revision:{' '}
|
||||||
|
</Column>
|
||||||
|
<Column sm={3} md={3} lg={3} className="grid-date">
|
||||||
|
{processInstance.bpmn_version_control_identifier} (
|
||||||
|
{processInstance.bpmn_version_control_type})
|
||||||
|
</Column>
|
||||||
|
</Grid>
|
||||||
<Grid condensed fullWidth>
|
<Grid condensed fullWidth>
|
||||||
<Column sm={1} md={1} lg={2} className="grid-list-title">
|
<Column sm={1} md={1} lg={2} className="grid-list-title">
|
||||||
Status:{' '}
|
Status:{' '}
|
||||||
|
@ -450,7 +400,6 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
||||||
</Tag>
|
</Tag>
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
{detailedViewElement()}
|
|
||||||
<br />
|
<br />
|
||||||
<Grid condensed fullWidth>
|
<Grid condensed fullWidth>
|
||||||
<Column sm={2} md={2} lg={2}>
|
<Column sm={2} md={2} lg={2}>
|
||||||
|
@ -493,7 +442,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
||||||
setShowProcessInstanceMetadata(true);
|
setShowProcessInstanceMetadata(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Metadata
|
Details
|
||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
</ButtonSet>
|
</ButtonSet>
|
||||||
|
@ -1012,7 +961,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
open={showProcessInstanceMetadata}
|
open={showProcessInstanceMetadata}
|
||||||
modalHeading="Metadata"
|
modalHeading="Details"
|
||||||
passiveModal
|
passiveModal
|
||||||
onRequestClose={() => setShowProcessInstanceMetadata(false)}
|
onRequestClose={() => setShowProcessInstanceMetadata(false)}
|
||||||
>
|
>
|
||||||
|
|
|
@ -19,6 +19,7 @@ import HttpService from '../services/HttpService';
|
||||||
import useAPIError from '../hooks/UseApiError';
|
import useAPIError from '../hooks/UseApiError';
|
||||||
import { modifyProcessIdentifierForPathParam } from '../helpers';
|
import { modifyProcessIdentifierForPathParam } from '../helpers';
|
||||||
import { ProcessInstanceTask } from '../interfaces';
|
import { ProcessInstanceTask } from '../interfaces';
|
||||||
|
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||||
|
|
||||||
export default function TaskShow() {
|
export default function TaskShow() {
|
||||||
const [task, setTask] = useState<ProcessInstanceTask | null>(null);
|
const [task, setTask] = useState<ProcessInstanceTask | null>(null);
|
||||||
|
@ -85,7 +86,6 @@ export default function TaskShow() {
|
||||||
successCallback: processSubmitResult,
|
successCallback: processSubmitResult,
|
||||||
failureCallback: (error: any) => {
|
failureCallback: (error: any) => {
|
||||||
addError(error);
|
addError(error);
|
||||||
setDisabled(false);
|
|
||||||
},
|
},
|
||||||
httpMethod: 'PUT',
|
httpMethod: 'PUT',
|
||||||
postBody: dataToSubmit,
|
postBody: dataToSubmit,
|
||||||
|
@ -270,7 +270,7 @@ export default function TaskShow() {
|
||||||
return (
|
return (
|
||||||
<div className="markdown">
|
<div className="markdown">
|
||||||
{/*
|
{/*
|
||||||
https://www.npmjs.com/package/@uiw/react-md-editor switches to dark mode by default by respecting @media (prefers-color-scheme: dark)
|
https://www.npmjs.com/package/@uiw/react-md-editor switches to dark mode by default by respecting @media (prefers-color-scheme: dark)
|
||||||
This makes it look like our site is broken, so until the rest of the site supports dark mode, turn off dark mode for this component.
|
This makes it look like our site is broken, so until the rest of the site supports dark mode, turn off dark mode for this component.
|
||||||
*/}
|
*/}
|
||||||
<div data-color-mode="light">
|
<div data-color-mode="light">
|
||||||
|
@ -288,6 +288,17 @@ export default function TaskShow() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main>
|
<main>
|
||||||
|
<ProcessBreadcrumb
|
||||||
|
hotCrumbs={[
|
||||||
|
[
|
||||||
|
`Process Instance Id: ${params.process_instance_id}`,
|
||||||
|
`/admin/process-instances/for-me/${modifyProcessIdentifierForPathParam(
|
||||||
|
task.process_model_identifier
|
||||||
|
)}/${params.process_instance_id}`,
|
||||||
|
],
|
||||||
|
[`Task: ${task.title || task.id}`],
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<div>{buildTaskNavigation()}</div>
|
<div>{buildTaskNavigation()}</div>
|
||||||
<h3>
|
<h3>
|
||||||
Task: {task.title} ({task.process_model_display_name}){statusString}
|
Task: {task.title} ({task.process_model_display_name}){statusString}
|
||||||
|
|
Loading…
Reference in New Issue