filtering by metadata works w/ burnettk

This commit is contained in:
jasquat 2022-12-02 13:47:04 -05:00
parent a4edb5d766
commit ae2bc38588
8 changed files with 172 additions and 52 deletions

View File

@ -785,7 +785,6 @@ def process_instance_list(
report_id: Optional[int] = None,
) -> flask.wrappers.Response:
"""Process_instance_list."""
process_instance_report = ProcessInstanceReportService.report_with_identifier(
g.user, report_id, report_identifier
)
@ -942,12 +941,18 @@ def process_instance_list(
if column["accessor"] in stock_columns:
continue
instance_metadata_alias = aliased(ProcessInstanceMetadataModel)
process_instance_query = process_instance_query.outerjoin(
filter_for_column = next((f for f in process_instance_report.report_metadata['filter_by'] if f['field_name'] == column['accessor']), None)
isouter = True
conditions = [ProcessInstanceModel.id == instance_metadata_alias.process_instance_id,
instance_metadata_alias.key == column["accessor"]]
if filter_for_column:
isouter = False
conditions.append(instance_metadata_alias.value == filter_for_column["field_value"])
process_instance_query = process_instance_query.join(
instance_metadata_alias,
and_(
ProcessInstanceModel.id == instance_metadata_alias.process_instance_id,
instance_metadata_alias.key == column["accessor"],
),
and_(*conditions),
isouter=isouter
).add_columns(func.max(instance_metadata_alias.value).label(column["accessor"]))
process_instances = (

View File

@ -29,8 +29,6 @@ class ProcessInstanceReportFilter:
"""To_dict."""
d = {}
print(f"dir(self): {dir(self)}")
if self.process_model_identifier is not None:
d["process_model_identifier"] = self.process_model_identifier
if self.start_from is not None:
@ -86,7 +84,7 @@ class ProcessInstanceReportService:
# TODO replace with system reports that are loaded on launch (or similar)
temp_system_metadata_map = {
"default": {"columns": cls.builtin_column_options()},
"default": {"columns": cls.builtin_column_options(), "filter_by": [], 'order_by': ['-start_in_seconds', '-id']},
"system_report_instances_initiated_by_me": {
"columns": [
{"Header": "id", "accessor": "id"},
@ -98,13 +96,13 @@ class ProcessInstanceReportService:
{"Header": "end_in_seconds", "accessor": "end_in_seconds"},
{"Header": "status", "accessor": "status"},
],
"filter_by": [{"field_name": "initiated_by_me", "field_value": True}],
"filter_by": [{"field_name": "initiated_by_me", "field_value": True}],'order_by': ['-start_in_seconds', '-id']
},
"system_report_instances_with_tasks_completed_by_me": {
"columns": cls.builtin_column_options(),
"filter_by": [
{"field_name": "with_tasks_completed_by_me", "field_value": True}
],
],'order_by': ['-start_in_seconds', '-id']
},
"system_report_instances_with_tasks_completed_by_my_groups": {
"columns": cls.builtin_column_options(),
@ -113,16 +111,15 @@ class ProcessInstanceReportService:
"field_name": "with_tasks_completed_by_my_group",
"field_value": True,
}
],
],'order_by': ['-start_in_seconds', '-id']
},
}
process_instance_report = ProcessInstanceReportModel(
identifier=report_identifier,
created_by_id=user.id,
report_metadata=temp_system_metadata_map[report_identifier], # type: ignore
report_metadata=temp_system_metadata_map[report_identifier],
)
# db.session.add(pro
return process_instance_report # type: ignore

View File

@ -6,12 +6,18 @@ import {
Stack,
// @ts-ignore
} from '@carbon/react';
import { ProcessInstanceReport, ProcessModel } from '../interfaces';
import {
ReportFilter,
ProcessInstanceReport,
ProcessModel,
ReportColumn,
ReportMetadata,
} from '../interfaces';
import HttpService from '../services/HttpService';
type OwnProps = {
onSuccess: (..._args: any[]) => any;
columnArray: { Header: string; accessor: string };
columnArray: ReportColumn[];
orderBy: string;
processModelSelection: ProcessModel | null;
processStatusSelection: string[];
@ -22,6 +28,7 @@ type OwnProps = {
buttonText?: string;
buttonClassName?: string;
processInstanceReportSelection?: ProcessInstanceReport | null;
reportMetadata: ReportMetadata;
};
export default function ProcessInstanceListSaveAsReport({
@ -37,6 +44,7 @@ export default function ProcessInstanceListSaveAsReport({
endToSeconds,
buttonText = 'Save as Perspective',
buttonClassName,
reportMetadata,
}: OwnProps) {
const [identifier, setIdentifier] = useState<string>(
processInstanceReportSelection?.identifier || ''
@ -59,7 +67,11 @@ export default function ProcessInstanceListSaveAsReport({
const addProcessInstanceReport = (event: any) => {
event.preventDefault();
const orderByArray = orderBy.split(',').filter((n) => n);
// TODO: make a field to set this
let orderByArray = ['-start_in_seconds', '-id'];
if (orderBy) {
orderByArray = orderBy.split(',').filter((n) => n);
}
const filterByArray: any = [];
if (processModelSelection) {
@ -72,7 +84,8 @@ export default function ProcessInstanceListSaveAsReport({
if (processStatusSelection.length > 0) {
filterByArray.push({
field_name: 'process_status',
field_value: processStatusSelection[0], // TODO: support more than one status
field_value: processStatusSelection.join(','),
operator: 'in',
});
}
@ -104,6 +117,17 @@ export default function ProcessInstanceListSaveAsReport({
});
}
reportMetadata.filter_by.forEach((reportFilter: ReportFilter) => {
columnArray.forEach((reportColumn: ReportColumn) => {
if (
reportColumn.accessor === reportFilter.field_name &&
reportColumn.filterable
) {
filterByArray.push(reportFilter);
}
});
});
let path = `/process-instances/reports`;
let httpMethod = 'POST';
if (isEditMode() && processInstanceReportSelection) {

View File

@ -57,6 +57,9 @@ import {
ProcessInstanceReport,
ProcessInstance,
ReportColumn,
ReportColumnForEditing,
ReportMetadata,
ReportFilter,
} from '../interfaces';
import ProcessModelSearch from './ProcessModelSearch';
import ProcessInstanceReportSearch from './ProcessInstanceReportSearch';
@ -98,7 +101,7 @@ export default function ProcessInstanceListTable({
const navigate = useNavigate();
const [processInstances, setProcessInstances] = useState([]);
const [reportMetadata, setReportMetadata] = useState({});
const [reportMetadata, setReportMetadata] = useState<ReportMetadata | null>();
const [pagination, setPagination] = useState<PaginationObject | null>(null);
const [processInstanceFilters, setProcessInstanceFilters] = useState({});
@ -143,7 +146,7 @@ export default function ProcessInstanceListTable({
const [showReportColumnForm, setShowReportColumnForm] =
useState<boolean>(false);
const [reportColumnToOperateOn, setReportColumnToOperateOn] =
useState<ReportColumn | null>(null);
useState<ReportColumnForEditing | null>(null);
const [reportColumnFormMode, setReportColumnFormMode] = useState<string>('');
const dateParametersToAlwaysFilterBy: dateParameters = useMemo(() => {
@ -630,17 +633,19 @@ export default function ProcessInstanceListTable({
endToSeconds,
} = calculateStartAndEndSeconds();
if (!valid) {
if (!valid || !reportMetadata) {
return null;
}
return (
<ProcessInstanceListSaveAsReport
onSuccess={onSaveReportSuccess}
buttonClassName="narrow-button"
columnArray={reportColumns()}
orderBy=""
buttonText="Save As New Perspective"
buttonText="Save New Perspective"
processModelSelection={processModelSelection}
processStatusSelection={processStatusSelection}
reportMetadata={reportMetadata}
startFromSeconds={startFromSeconds}
startToSeconds={startToSeconds}
endFromSeconds={endFromSeconds}
@ -650,12 +655,14 @@ export default function ProcessInstanceListTable({
};
const removeColumn = (reportColumn: ReportColumn) => {
const reportMetadataCopy = { ...reportMetadata };
const newColumns = reportColumns().filter(
(rc: ReportColumn) => rc.accessor !== reportColumn.accessor
);
Object.assign(reportMetadataCopy, { columns: newColumns });
setReportMetadata(reportMetadataCopy);
if (reportMetadata) {
const reportMetadataCopy = { ...reportMetadata };
const newColumns = reportColumns().filter(
(rc: ReportColumn) => rc.accessor !== reportColumn.accessor
);
Object.assign(reportMetadataCopy, { columns: newColumns });
setReportMetadata(reportMetadataCopy);
}
};
const handleColumnFormClose = () => {
@ -664,8 +671,49 @@ export default function ProcessInstanceListTable({
setReportColumnToOperateOn(null);
};
const handleUpdateColumn = () => {
if (reportColumnToOperateOn) {
const getFilterByFromReportMetadata = (reportColumnAccessor: string) => {
if (reportMetadata) {
return reportMetadata.filter_by.find((reportFilter: ReportFilter) => {
return reportColumnAccessor === reportFilter.field_name;
});
}
return null;
};
const getNewFiltersFromReportForEditing = (
reportColumnForEditing: ReportColumnForEditing
) => {
if (!reportMetadata) {
return null;
}
const reportMetadataCopy = { ...reportMetadata };
let newReportFilters = reportMetadataCopy.filter_by;
if (reportColumnForEditing.filterable) {
const newReportFilter: ReportFilter = {
field_name: reportColumnForEditing.accessor,
field_value: reportColumnForEditing.filter_field_value,
operator: reportColumnForEditing.filter_operator || 'equals',
};
const existingReportFilter = getFilterByFromReportMetadata(
reportColumnForEditing.accessor
);
if (existingReportFilter) {
const existingReportFilterIndex =
reportMetadataCopy.filter_by.indexOf(existingReportFilter);
if (reportColumnForEditing.filter_field_value) {
newReportFilters[existingReportFilterIndex] = newReportFilter;
} else {
newReportFilters.splice(existingReportFilterIndex, 1);
}
} else {
newReportFilters = newReportFilters.concat([newReportFilter]);
}
}
return newReportFilters;
};
const handleUpdateReportColumn = () => {
if (reportColumnToOperateOn && reportMetadata) {
const reportMetadataCopy = { ...reportMetadata };
let newReportColumns = null;
if (reportColumnFormMode === 'new') {
@ -680,6 +728,7 @@ export default function ProcessInstanceListTable({
}
Object.assign(reportMetadataCopy, {
columns: newReportColumns,
filter_by: getNewFiltersFromReportForEditing(reportColumnToOperateOn),
});
setReportMetadata(reportMetadataCopy);
setReportColumnToOperateOn(null);
@ -688,8 +737,27 @@ export default function ProcessInstanceListTable({
}
};
const reportColumnToReportColumnForEditing = (reportColumn: ReportColumn) => {
const reportColumnForEditing: ReportColumnForEditing = Object.assign(
reportColumn,
{ filter_field_value: '', filter_operator: '' }
);
const reportFilter = getFilterByFromReportMetadata(
reportColumnForEditing.accessor
);
if (reportFilter) {
reportColumnForEditing.filter_field_value = reportFilter.field_value;
reportColumnForEditing.filter_operator =
reportFilter.operator || 'equals';
}
return reportColumnForEditing;
};
const updateReportColumn = (event: any) => {
setReportColumnToOperateOn(event.selectedItem);
const reportColumnForEditing = reportColumnToReportColumnForEditing(
event.selectedItem
);
setReportColumnToOperateOn(reportColumnForEditing);
};
// options includes item and inputValue
@ -709,7 +777,7 @@ export default function ProcessInstanceListTable({
const reportColumnToOperateOnCopy = {
...reportColumnToOperateOn,
};
reportColumnToOperateOnCopy.condition_value = event.target.value;
reportColumnToOperateOnCopy.filter_field_value = event.target.value;
setReportColumnToOperateOn(reportColumnToOperateOnCopy);
}
};
@ -737,7 +805,6 @@ export default function ProcessInstanceListTable({
/>,
];
if (reportColumnToOperateOn && reportColumnToOperateOn.filterable) {
console.log('reportColumnToOperateOn', reportColumnToOperateOn);
formElements.push(
<TextInput
id="report-column-condition-value"
@ -745,7 +812,7 @@ export default function ProcessInstanceListTable({
labelText="Condition Value"
value={
reportColumnToOperateOn
? reportColumnToOperateOn.condition_value
? reportColumnToOperateOn.filter_field_value
: ''
}
onChange={setReportColumnConditionValue}
@ -785,7 +852,7 @@ export default function ProcessInstanceListTable({
modalHeading={modalHeading}
primaryButtonText="Save"
primaryButtonDisabled={!reportColumnToOperateOn}
onRequestSubmit={handleUpdateColumn}
onRequestSubmit={handleUpdateReportColumn}
onRequestClose={handleColumnFormClose}
hasScrollingContent
>
@ -799,13 +866,16 @@ export default function ProcessInstanceListTable({
const tags: any = [];
(reportColumns() as any).forEach((reportColumn: ReportColumn) => {
const reportColumnForEditing =
reportColumnToReportColumnForEditing(reportColumn);
let tagType = 'cool-gray';
if (reportColumn.filterable) {
if (reportColumnForEditing.filterable) {
tagType = 'green';
}
let reportColumnLabel = reportColumn.Header;
if (reportColumn.condition_value) {
reportColumnLabel = `${reportColumnLabel}=${reportColumn.condition_value}`;
let reportColumnLabel = reportColumnForEditing.Header;
if (reportColumnForEditing.filter_field_value) {
reportColumnLabel = `${reportColumnLabel}=${reportColumnForEditing.filter_field_value}`;
}
tags.push(
<Tag type={tagType} size="sm">
@ -813,9 +883,9 @@ export default function ProcessInstanceListTable({
kind="ghost"
size="sm"
className="button-tag-icon"
title={`Edit ${reportColumn.accessor}`}
title={`Edit ${reportColumnForEditing.accessor}`}
onClick={() => {
setReportColumnToOperateOn(reportColumn);
setReportColumnToOperateOn(reportColumnForEditing);
setShowReportColumnForm(true);
setReportColumnFormMode('edit');
}}
@ -830,7 +900,7 @@ export default function ProcessInstanceListTable({
hasIconOnly
size="sm"
kind="ghost"
onClick={() => removeColumn(reportColumn)}
onClick={() => removeColumn(reportColumnForEditing)}
/>
</Tag>
);
@ -933,11 +1003,14 @@ export default function ProcessInstanceListTable({
</Column>
</Grid>
<Grid fullWidth className="with-bottom-margin">
<Column md={4}>
<Column sm={4} md={4} lg={8}>
{saveAsReportComponent()}
</Column>
<Column sm={4} md={4} lg={8}>
<ButtonSet>
<Button
kind=""
className="button-white-background"
className="button-white-background narrow-button"
onClick={clearFilters}
>
Clear
@ -946,17 +1019,13 @@ export default function ProcessInstanceListTable({
kind="secondary"
onClick={applyFilter}
data-qa="filter-button"
className="narrow-button"
>
Filter
</Button>
</ButtonSet>
</Column>
</Grid>
<Grid fullWidth className="with-bottom-margin">
<Column md={7} lg={13} sm={3}>
{saveAsReportComponent()}
</Column>
</Grid>
</>
);
};
@ -1079,7 +1148,11 @@ export default function ProcessInstanceListTable({
/>
</Column>,
];
if (processInstanceReportSelection && showFilterOptions) {
if (
processInstanceReportSelection &&
showFilterOptions &&
reportMetadata
) {
columns.push(
<Column sm={2} md={4} lg={2}>
<ProcessInstanceListSaveAsReport
@ -1090,6 +1163,7 @@ export default function ProcessInstanceListTable({
buttonText="Save"
processModelSelection={processModelSelection}
processStatusSelection={processStatusSelection}
reportMetadata={reportMetadata}
startFromSeconds={startFromSeconds}
startToSeconds={startToSeconds}
endFromSeconds={endFromSeconds}

View File

@ -41,7 +41,7 @@ export default function ProcessInstanceReportSearch({
const reportSelectionString = (
processInstanceReport: ProcessInstanceReport
) => {
return `${truncateString(processInstanceReport.identifier, 20)} (${
return `${truncateString(processInstanceReport.identifier, 20)} (Id: ${
processInstanceReport.id
})`;
};

View File

@ -14,6 +14,7 @@ export const PROCESS_STATUSES = [
'complete',
'error',
'suspended',
'terminated',
];
// with time: yyyy-MM-dd HH:mm:ss

View File

@ -346,3 +346,10 @@ td.actions-cell {
.combo-box-in-modal {
height: 300px;
}
.cds--btn.narrow-button {
max-width: 10rem;
min-width: 5rem;
word-break: normal;
}

View File

@ -63,15 +63,27 @@ export interface MessageInstance {
message_correlations?: MessageCorrelations;
}
export interface ReportFilter {
field_name: string;
field_value: string;
operator?: string;
}
export interface ReportColumn {
Header: string;
accessor: string;
filterable: boolean;
condition_value?: string;
}
export interface ReportColumnForEditing extends ReportColumn {
filter_field_value: string;
filter_operator: string;
}
export interface ReportMetadata {
columns: ReportColumn[];
filter_by: ReportFilter[];
order_by: string[];
}
export interface ProcessInstanceReport {