diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/api.yml b/spiffworkflow-backend/src/spiffworkflow_backend/api.yml index 0f0a49c2..1ef9cf67 100755 --- a/spiffworkflow-backend/src/spiffworkflow_backend/api.yml +++ b/spiffworkflow-backend/src/spiffworkflow_backend/api.yml @@ -153,7 +153,6 @@ paths: description: The number of groups to show per page. Defaults to page 10. schema: type: integer - # process_groups_list get: operationId: spiffworkflow_backend.routes.process_api_blueprint.process_groups_list summary: get list @@ -168,7 +167,6 @@ paths: type: array items: $ref: "#/components/schemas/ProcessModelCategory" - # process_group_add post: operationId: spiffworkflow_backend.routes.process_api_blueprint.process_group_add summary: Add process group @@ -429,7 +427,7 @@ paths: description: For filtering - beginning of start window - in seconds since epoch schema: type: integer - - name: start_till + - name: start_to in: query required: false description: For filtering - end of start window - in seconds since epoch @@ -441,7 +439,7 @@ paths: description: For filtering - beginning of end window - in seconds since epoch schema: type: integer - - name: end_till + - name: end_to in: query required: false description: For filtering - end of end window - in seconds since epoch diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/process_group.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_group.py index 0b100ed4..381f8f63 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/process_group.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_group.py @@ -1,6 +1,7 @@ """Process_group.""" from __future__ import annotations +import dataclasses from dataclasses import dataclass from dataclasses import field from typing import Any @@ -20,6 +21,7 @@ class ProcessGroup: id: str # A unique string name, lower case, under scores (ie, 'my_group') display_name: str + description: str | None = None display_order: int | None = 0 admin: bool | None = False process_models: list[ProcessModelInfo] = field( @@ -38,6 +40,12 @@ class ProcessGroup: return True return False + @property + def serialized(self) -> dict: + """Serialized.""" + original_dict = dataclasses.asdict(self) + return {x: original_dict[x] for x in original_dict if x not in ["sort_index"]} + class ProcessGroupSchema(Schema): """ProcessGroupSchema.""" diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/process_model.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_model.py index 9558a79b..1928f312 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/process_model.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_model.py @@ -30,7 +30,6 @@ class ProcessModelInfo: display_name: str description: str process_group_id: str = "" - process_group: Any | None = None primary_file_name: str | None = None primary_process_id: str | None = None display_order: int | None = 0 diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py index 41cd9d99..4ff25a75 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -43,6 +43,7 @@ from spiffworkflow_backend.models.message_triggerable_process_model import ( MessageTriggerableProcessModel, ) from spiffworkflow_backend.models.principal import PrincipalModel +from spiffworkflow_backend.models.process_group import ProcessGroup from spiffworkflow_backend.models.process_group import ProcessGroupSchema from spiffworkflow_backend.models.process_instance import ProcessInstanceApiSchema from spiffworkflow_backend.models.process_instance import ProcessInstanceModel @@ -135,18 +136,12 @@ def permissions_check(body: Dict[str, Dict[str, list[str]]]) -> flask.wrappers.R return make_response(jsonify({"results": response_dict}), 200) -def process_group_add( - body: Dict[str, Union[str, bool, int]] -) -> flask.wrappers.Response: +def process_group_add(body: dict) -> flask.wrappers.Response: """Add_process_group.""" process_model_service = ProcessModelService() - process_group = ProcessGroupSchema().load(body) + process_group = ProcessGroup(**body) process_model_service.add_process_group(process_group) - return Response( - json.dumps(ProcessGroupSchema().dump(process_group)), - status=201, - mimetype="application/json", - ) + return make_response(jsonify(process_group), 201) def process_group_delete(process_group_id: str) -> flask.wrappers.Response: @@ -155,13 +150,18 @@ def process_group_delete(process_group_id: str) -> flask.wrappers.Response: return Response(json.dumps({"ok": True}), status=200, mimetype="application/json") -def process_group_update( - process_group_id: str, body: Dict[str, Union[str, bool, int]] -) -> Dict[str, Union[str, bool, int]]: +def process_group_update(process_group_id: str, body: dict) -> flask.wrappers.Response: """Process Group Update.""" - process_group = ProcessGroupSchema().load(body) + body_include_list = ["display_name", "description"] + body_filtered = { + include_item: body[include_item] + for include_item in body_include_list + if include_item in body + } + + process_group = ProcessGroup(id=process_group_id, **body_filtered) ProcessModelService().update_process_group(process_group) - return ProcessGroupSchema().dump(process_group) # type: ignore + return make_response(jsonify(process_group), 200) def process_groups_list(page: int = 1, per_page: int = 100) -> flask.wrappers.Response: @@ -174,6 +174,7 @@ def process_groups_list(page: int = 1, per_page: int = 100) -> flask.wrappers.Re remainder = len(process_groups) % per_page if remainder > 0: pages += 1 + response_json = { "results": ProcessGroupSchema(many=True).dump(batch), "pagination": { @@ -199,7 +200,7 @@ def process_group_show( status_code=400, ) ) from exception - return ProcessGroupSchema().dump(process_group) + return make_response(jsonify(process_group), 200) def process_model_add( @@ -225,7 +226,6 @@ def process_model_add( status_code=400, ) - process_model_info.process_group = process_group process_model_service.add_spec(process_model_info) return Response( json.dumps(ProcessModelInfoSchema().dump(process_model_info)), @@ -651,9 +651,9 @@ def process_instance_list( page: int = 1, per_page: int = 100, start_from: Optional[int] = None, - start_till: Optional[int] = None, + start_to: Optional[int] = None, end_from: Optional[int] = None, - end_till: Optional[int] = None, + end_to: Optional[int] = None, process_status: Optional[str] = None, ) -> flask.wrappers.Response: """Process_instance_list.""" @@ -684,17 +684,17 @@ def process_instance_list( process_instance_query = process_instance_query.filter( ProcessInstanceModel.start_in_seconds >= start_from ) - if start_till is not None: + if start_to is not None: process_instance_query = process_instance_query.filter( - ProcessInstanceModel.start_in_seconds <= start_till + ProcessInstanceModel.start_in_seconds <= start_to ) if end_from is not None: process_instance_query = process_instance_query.filter( ProcessInstanceModel.end_in_seconds >= end_from ) - if end_till is not None: + if end_to is not None: process_instance_query = process_instance_query.filter( - ProcessInstanceModel.end_in_seconds <= end_till + ProcessInstanceModel.end_in_seconds <= end_to ) if process_status is not None: process_status_array = process_status.split(",") diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_model_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_model_service.py index 57d84229..e10092d5 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_model_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_model_service.py @@ -170,7 +170,7 @@ class ProcessModelService(FileSystemService): json_path = os.path.join(cat_path, self.CAT_JSON_FILE) with open(json_path, "w") as cat_json: json.dump( - self.GROUP_SCHEMA.dump(process_group), + process_group.serialized, cat_json, indent=4, sort_keys=True, @@ -274,6 +274,5 @@ class ProcessModelService(FileSystemService): with open(spec_path, "w") as wf_json: json.dump(self.WF_SCHEMA.dump(spec), wf_json, indent=4) if process_group: - spec.process_group = process_group spec.process_group_id = process_group.id return spec diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py index 7ac6b923..bad47ce9 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py @@ -17,7 +17,6 @@ from spiffworkflow_backend.exceptions.process_entity_not_found_error import ( from spiffworkflow_backend.models.active_task import ActiveTaskModel from spiffworkflow_backend.models.group import GroupModel from spiffworkflow_backend.models.process_group import ProcessGroup -from spiffworkflow_backend.models.process_group import ProcessGroupSchema from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus from spiffworkflow_backend.models.process_instance_report import ( @@ -388,25 +387,29 @@ class TestProcessApi(BaseTest): display_name="Another Test Category", display_order=0, admin=False, + description="Test Description", ) response = client.post( "/v1.0/process-groups", headers=self.logged_in_headers(with_super_admin_user), content_type="application/json", - data=json.dumps(ProcessGroupSchema().dump(process_group)), + data=json.dumps(process_group.serialized), ) assert response.status_code == 201 + assert response.json # Check what is returned - result = ProcessGroupSchema().loads(response.get_data(as_text=True)) + result = ProcessGroup(**response.json) assert result is not None assert result.display_name == "Another Test Category" assert result.id == "test" + assert result.description == "Test Description" # Check what is persisted persisted = ProcessModelService().get_process_group("test") assert persisted.display_name == "Another Test Category" assert persisted.id == "test" + assert persisted.description == "Test Description" def test_process_group_delete( self, @@ -461,7 +464,7 @@ class TestProcessApi(BaseTest): f"/v1.0/process-groups/{group_id}", headers=self.logged_in_headers(with_super_admin_user), content_type="application/json", - data=json.dumps(ProcessGroupSchema().dump(process_group)), + data=json.dumps(process_group.serialized), ) assert response.status_code == 200 @@ -788,6 +791,7 @@ class TestProcessApi(BaseTest): f"/v1.0/process-groups/{test_process_group_id}", headers=self.logged_in_headers(with_super_admin_user), ) + assert response.status_code == 200 assert response.json is not None assert response.json["id"] == test_process_group_id @@ -1299,7 +1303,7 @@ class TestProcessApi(BaseTest): # start > 2000, end < 5000 - this should eliminate the first 2 and the last response = client.get( - "/v1.0/process-instances?start_from=2001&end_till=5999", + "/v1.0/process-instances?start_from=2001&end_to=5999", headers=self.logged_in_headers(with_super_admin_user), ) assert response.json is not None @@ -1310,7 +1314,7 @@ class TestProcessApi(BaseTest): # start > 1000, start < 4000 - this should eliminate the first and the last 2 response = client.get( - "/v1.0/process-instances?start_from=1001&start_till=3999", + "/v1.0/process-instances?start_from=1001&start_to=3999", headers=self.logged_in_headers(with_super_admin_user), ) assert response.json is not None @@ -1321,7 +1325,7 @@ class TestProcessApi(BaseTest): # end > 2000, end < 6000 - this should eliminate the first and the last response = client.get( - "/v1.0/process-instances?end_from=2001&end_till=5999", + "/v1.0/process-instances?end_from=2001&end_to=5999", headers=self.logged_in_headers(with_super_admin_user), ) assert response.json is not None diff --git a/spiffworkflow-frontend/cypress.config.js b/spiffworkflow-frontend/cypress.config.js index c4bf94c4..1c8c1c6e 100644 --- a/spiffworkflow-frontend/cypress.config.js +++ b/spiffworkflow-frontend/cypress.config.js @@ -10,4 +10,9 @@ module.exports = defineConfig({ // implement node event listeners here }, }, + + // this scrolls away from the elements for some reason with carbon when set to top + // https://github.com/cypress-io/cypress/issues/2353 + // https://docs.cypress.io/guides/core-concepts/interacting-with-elements#Scrolling + scrollBehavior: "center", }); diff --git a/spiffworkflow-frontend/cypress/e2e/process_groups.cy.js b/spiffworkflow-frontend/cypress/e2e/process_groups.cy.js index 1f2c675e..629b18c6 100644 --- a/spiffworkflow-frontend/cypress/e2e/process_groups.cy.js +++ b/spiffworkflow-frontend/cypress/e2e/process_groups.cy.js @@ -32,7 +32,7 @@ describe('process-groups', () => { cy.contains('Delete').click(); cy.contains('Are you sure'); - cy.contains('OK').click(); + cy.getBySel('modal-confirmation-dialog').find('.cds--btn--danger').click(); cy.url().should('include', `process-groups`); cy.contains(groupId).should('not.exist'); }); diff --git a/spiffworkflow-frontend/cypress/e2e/process_instances.cy.js b/spiffworkflow-frontend/cypress/e2e/process_instances.cy.js index d5383d5a..b7bbf9d4 100644 --- a/spiffworkflow-frontend/cypress/e2e/process_instances.cy.js +++ b/spiffworkflow-frontend/cypress/e2e/process_instances.cy.js @@ -43,12 +43,19 @@ const updateBpmnPythonScriptWithMonaco = ( cy.contains('Launch Editor').click(); // sometimes, Loading... appears for more than 4 seconds. not sure why. cy.contains('Loading...').should('not.exist'); + + // the delay 30 is because, at some point, monaco started automatically + // adding a second double quote when we type a double quote. when it does + // that, there is a race condition where it sometimes gets in more text + // before the second double quote appears because the robot is typing faster + // than a human being could, so we artificially slow it down to make it more + // human. cy.get('.monaco-editor textarea:first') .click() .focused() // change subject to currently focused element // .type('{ctrl}a') // had been doing it this way, but it turns out to be flaky relative to clear() .clear() - .type(pythonScript); + .type(pythonScript, { delay: 30 }); cy.contains('Close').click(); // wait for a little bit for the xml to get set before saving @@ -111,8 +118,10 @@ describe('process-instances', () => { }); it('can create a new instance and can modify with monaco text editor', () => { - const originalPythonScript = 'person = "Kevin"'; - const newPythonScript = 'person = "Mike"'; + // leave off the ending double quote since manco adds it + const originalPythonScript = 'person = "Kevin'; + const newPythonScript = 'person = "Mike'; + const bpmnFile = 'process_model_one.bpmn'; // Change bpmn diff --git a/spiffworkflow-frontend/cypress/e2e/process_models.cy.js b/spiffworkflow-frontend/cypress/e2e/process_models.cy.js index 3b28514b..48b65d5d 100644 --- a/spiffworkflow-frontend/cypress/e2e/process_models.cy.js +++ b/spiffworkflow-frontend/cypress/e2e/process_models.cy.js @@ -99,7 +99,7 @@ describe('process-models', () => { cy.contains(/^Process Model File$/); // Some reason, cypress evals json strings so we have to escape it it with '{{}' cy.get('.view-line').type('{{} "test_key": "test_value" }'); - cy.contains('Save').click(); + cy.getBySel('file-save-button').click(); cy.get('input[name=file_name]').type(jsonFileName); cy.contains('Save Changes').click(); cy.contains(`Process Model File: ${jsonFileName}`); @@ -168,12 +168,8 @@ describe('process-models', () => { }); it('can allow searching for model', () => { - cy.get('[name=process-model-selection]').click(); - cy.get('[name=process-model-selection]').type('model-3'); - cy.get( - `[aria-label="acceptance-tests-group-one/acceptance-tests-model-3"]` - ).click(); - - cy.contains('Process Instances').click(); + cy.getBySel('process-model-selection').click().type('model-3'); + cy.contains('acceptance-tests-group-one/acceptance-tests-model-3').click(); + cy.contains('List').click(); }); }); diff --git a/spiffworkflow-frontend/cypress/e2e/tasks.cy.js b/spiffworkflow-frontend/cypress/e2e/tasks.cy.js index 86298f59..377b05ac 100644 --- a/spiffworkflow-frontend/cypress/e2e/tasks.cy.js +++ b/spiffworkflow-frontend/cypress/e2e/tasks.cy.js @@ -21,6 +21,7 @@ describe('tasks', () => { cy.logout(); }); + // TODO: need to fix the next_task thing to make this pass it('can complete and navigate a form', () => { const groupDisplayName = 'Acceptance Tests Group One'; const modelId = `acceptance-tests-model-2`; diff --git a/spiffworkflow-frontend/cypress/support/commands.js b/spiffworkflow-frontend/cypress/support/commands.js index 1b9c9241..affce0d1 100644 --- a/spiffworkflow-frontend/cypress/support/commands.js +++ b/spiffworkflow-frontend/cypress/support/commands.js @@ -31,11 +31,13 @@ Cypress.Commands.add('getBySel', (selector, ...args) => { }); Cypress.Commands.add('navigateToHome', () => { - cy.getBySel('nav-home').click(); + cy.get('button[aria-label="Open menu"]').click(); + cy.getBySel('side-nav-items').contains('Home').click(); + // cy.getBySel('nav-home').click(); }); Cypress.Commands.add('navigateToAdmin', () => { - cy.getBySel('spiffworkflow-logo').click(); + cy.visit('/admin'); }); Cypress.Commands.add('login', (selector, ...args) => { @@ -101,18 +103,15 @@ Cypress.Commands.add( ); Cypress.Commands.add('basicPaginationTest', () => { - cy.get('#pagination-page-dropdown') - .type('typing_to_open_dropdown_box....FIXME') - .find('.dropdown-item') - .contains(/^2$/) - .click(); + cy.getBySel('pagination-options').scrollIntoView(); + cy.get('.cds--select__item-count').find('.cds--select-input').select('2'); - cy.contains(/^1-2 of \d+$/); - cy.getBySel('pagination-previous-button-inactive'); - cy.getBySel('pagination-next-button').click(); - cy.contains(/^3-4 of \d+$/); - cy.getBySel('pagination-previous-button').click(); - cy.contains(/^1-2 of \d+$/); + // NOTE: this is a em dash instead of en dash + cy.contains(/\b1–2 of \d+/); + cy.get('.cds--pagination__button--forward').click(); + cy.contains(/\b3–4 of \d+/); + cy.get('.cds--pagination__button--backward').click(); + cy.contains(/\b1–2 of \d+/); }); Cypress.Commands.add('assertAtLeastOneItemInPaginatedResults', () => { diff --git a/spiffworkflow-frontend/package-lock.json b/spiffworkflow-frontend/package-lock.json index 08286743..a08036b5 100644 --- a/spiffworkflow-frontend/package-lock.json +++ b/spiffworkflow-frontend/package-lock.json @@ -11,6 +11,9 @@ "@babel/core": "^7.18.10", "@babel/plugin-transform-react-jsx": "^7.18.6", "@babel/preset-react": "^7.18.6", + "@carbon/icons-react": "^11.10.0", + "@carbon/react": "^1.16.0", + "@carbon/styles": "^1.16.0", "@ginkgo-bioworks/react-json-schema-form-builder": "^2.9.0", "@monaco-editor/react": "^4.4.5", "@rjsf/core": "^4.2.0", @@ -2140,6 +2143,138 @@ "resolved": "https://registry.npmjs.org/@camunda/zeebe-element-templates-json-schema/-/zeebe-element-templates-json-schema-0.6.0.tgz", "integrity": "sha512-qawIFM52lp1hW2vWrHaX8ywguZsp2olE0DRTHUY+KWH5GwszZwGWECP3tji1KVih2TasQyf28kcQVh8TeQ6dAg==" }, + "node_modules/@carbon/colors": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/@carbon/colors/-/colors-11.7.0.tgz", + "integrity": "sha512-2B57vtirYTpxGg7p9yIO+s4cwL5QB8ogGQB5Pz+zdaHoVxrLsGlxAg28CQgk7yxw7doqST79bRVYS6FaJq+qJw==" + }, + "node_modules/@carbon/feature-flags": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@carbon/feature-flags/-/feature-flags-0.9.0.tgz", + "integrity": "sha512-uNCRkxsNwLdJVNwQ5S5vrLAm4yawWzhFBwyP9EgXVmRzJH85Aim+miC+QNjRXntJDYhZYDuLABTeb3VD692ypA==" + }, + "node_modules/@carbon/grid": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/@carbon/grid/-/grid-11.7.0.tgz", + "integrity": "sha512-OCDXQNSPVOoBQN08Qn5wo2WpKRGRm/kEBo6ZTl2NoDCl21mcYJZ0IDbKPTukixJB1sUNDUlnrpwMoaznPj48dw==", + "dependencies": { + "@carbon/layout": "^11.7.0" + } + }, + "node_modules/@carbon/icon-helpers": { + "version": "10.34.0", + "resolved": "https://registry.npmjs.org/@carbon/icon-helpers/-/icon-helpers-10.34.0.tgz", + "integrity": "sha512-Ov9EBc1tR/DDrMI0pN1drj2jb27ISmYFBLdDji+aivVJkLPy8R/jikJOsOBgIq2kUjQJYNN199k2acHKjZdYIg==" + }, + "node_modules/@carbon/icons-react": { + "version": "11.10.0", + "resolved": "https://registry.npmjs.org/@carbon/icons-react/-/icons-react-11.10.0.tgz", + "integrity": "sha512-807RWTfbvVzmsDg2DJ4FjwYNbJSgkrEd1Ui8I07YheJVb3sbYGGZMG7aCS0qXVlrQOhB2hggtxSW1w9NksUXNA==", + "hasInstallScript": true, + "dependencies": { + "@carbon/icon-helpers": "^10.34.0", + "@carbon/telemetry": "0.1.0", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": ">=16" + } + }, + "node_modules/@carbon/layout": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/@carbon/layout/-/layout-11.7.0.tgz", + "integrity": "sha512-p4YQvW8U5Go0Tz1PZZgllGSPmoq8xBB5PHByuHiAjzwGclxPsBmY6Ea7tftINFW8VlcjDcampyT8VfZXhP2lFg==" + }, + "node_modules/@carbon/motion": { + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/@carbon/motion/-/motion-11.5.0.tgz", + "integrity": "sha512-5QEALh+xZzICdgVLanSpiDfBTErzVgEze/xUKs7ZdSbd6p1FaDKDGvCmj9RCsaz/CMVHIWo65MshIglSWX5Xvw==" + }, + "node_modules/@carbon/react": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@carbon/react/-/react-1.16.0.tgz", + "integrity": "sha512-kVeL/iyVqN2tfcoE1xliIm4w2ex9L4m/b8KuGo7ZuqBmRzANQdfSYGfj11KU0TXT1CbOVFrqsT/aBxApsP5IDg==", + "hasInstallScript": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "@carbon/feature-flags": "^0.9.0", + "@carbon/icons-react": "^11.10.0", + "@carbon/layout": "^11.7.0", + "@carbon/styles": "^1.16.0", + "@carbon/telemetry": "0.1.0", + "classnames": "2.3.2", + "copy-to-clipboard": "^3.3.1", + "downshift": "5.2.1", + "flatpickr": "4.6.9", + "invariant": "^2.2.3", + "lodash.debounce": "^4.0.8", + "lodash.findlast": "^4.5.0", + "lodash.isequal": "^4.5.0", + "lodash.omit": "^4.5.0", + "lodash.throttle": "^4.1.1", + "prop-types": "^15.7.2", + "react-is": "^17.0.2", + "use-resize-observer": "^6.0.0", + "wicg-inert": "^3.1.1", + "window-or-global": "^1.0.1" + }, + "peerDependencies": { + "react": "^16.8.6 || ^17.0.1", + "react-dom": "^16.8.6 || ^17.0.1", + "sass": "^1.33.0" + } + }, + "node_modules/@carbon/react/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/@carbon/styles": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@carbon/styles/-/styles-1.16.0.tgz", + "integrity": "sha512-LSjRw2Ws8rWI1a96KYUuX10jG+rpSn68dHlZhhDq+RJWsMGpjFhKUxPoTiJli2hHXyxey6rXV0hfr7oBJ0ud7w==", + "dependencies": { + "@carbon/colors": "^11.7.0", + "@carbon/feature-flags": "^0.9.0", + "@carbon/grid": "^11.7.0", + "@carbon/layout": "^11.7.0", + "@carbon/motion": "^11.5.0", + "@carbon/themes": "^11.11.0", + "@carbon/type": "^11.11.0", + "@ibm/plex": "6.0.0-next.6" + }, + "peerDependencies": { + "sass": "^1.33.0" + } + }, + "node_modules/@carbon/telemetry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@carbon/telemetry/-/telemetry-0.1.0.tgz", + "integrity": "sha512-kNWt0bkgPwGW0i5h7HFuljbKRXPvIhsKbB+1tEURAYLXoJg9iJLF1eGvWN5iVoFCS2zje4GR3OGOsvvKVe7Hlg==", + "bin": { + "carbon-telemetry": "bin/carbon-telemetry.js" + } + }, + "node_modules/@carbon/themes": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@carbon/themes/-/themes-11.11.0.tgz", + "integrity": "sha512-EhLizr2oMqJXNubI2zWw09qcSPLZdWoBOQ6uNcjHzpXgoGNMwbVJE/qGMy/ivr+EOs6Fe0z5T0u97v+ZhSmRhg==", + "dependencies": { + "@carbon/colors": "^11.7.0", + "@carbon/layout": "^11.7.0", + "@carbon/type": "^11.11.0", + "color": "^4.0.0" + } + }, + "node_modules/@carbon/type": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@carbon/type/-/type-11.11.0.tgz", + "integrity": "sha512-eX6z8BibP1En1xBm2wUd01Nzk0Tm1jftR2QSD4JBn4xhnkGR824gpcbLTAIMGx9/Mr3R65Enbam3uFO0OOaH8g==", + "dependencies": { + "@carbon/grid": "^11.7.0", + "@carbon/layout": "^11.7.0" + } + }, "node_modules/@codemirror/autocomplete": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.3.0.tgz", @@ -2899,6 +3034,14 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" }, + "node_modules/@ibm/plex": { + "version": "6.0.0-next.6", + "resolved": "https://registry.npmjs.org/@ibm/plex/-/plex-6.0.0-next.6.tgz", + "integrity": "sha512-B3uGruTn2rS5gweynLmfSe7yCawSRsJguJJQHVQiqf4rh2RNgJFu8YLE2Zd/JHV0ZXoVMOslcXP2k3hMkxKEyA==", + "engines": { + "node": ">=14" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -8009,9 +8152,9 @@ } }, "node_modules/classnames": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", - "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" }, "node_modules/clean-css": { "version": "5.3.1", @@ -8207,6 +8350,18 @@ "node": ">=0.10.0" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -8220,6 +8375,31 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", @@ -8484,6 +8664,14 @@ "node": ">=0.10.0" } }, + "node_modules/copy-to-clipboard": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.2.tgz", + "integrity": "sha512-Vme1Z6RUDzrb6xAI7EZlVZ5uvOk2F//GaxKUxajDqm9LhOVM1inxNAD2vy+UZDYsd0uyA9s7b3/FVZPSxqrCfg==", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, "node_modules/core_d": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/core_d/-/core_d-5.0.1.tgz", @@ -9005,9 +9193,9 @@ "integrity": "sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==" }, "node_modules/cypress": { - "version": "10.8.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.8.0.tgz", - "integrity": "sha512-QVse0dnLm018hgti2enKMVZR9qbIO488YGX06nH5j3Dg1isL38DwrBtyrax02CANU6y8F4EJUuyW6HJKw1jsFA==", + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.11.0.tgz", + "integrity": "sha512-lsaE7dprw5DoXM00skni6W5ElVVLGAdRUUdZjX2dYsGjbY/QnpzWZ95Zom1mkGg0hAaO/QVTZoFVS7Jgr/GUPA==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -9872,6 +10060,25 @@ "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" }, + "node_modules/downshift": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/downshift/-/downshift-5.2.1.tgz", + "integrity": "sha512-uHX2OLbWthLR8QbR8NCI8OmjvvJxq8+PrA95KblFd9JyB1zVZh1HnszzsWMMCnMuH6IvsUtVfF5HY7XfijJ2dw==", + "dependencies": { + "@babel/runtime": "^7.9.1", + "compute-scroll-into-view": "^1.0.13", + "prop-types": "^15.7.2", + "react-is": "^16.13.1" + }, + "peerDependencies": { + "react": ">=0.14.9" + } + }, + "node_modules/downshift/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -11596,6 +11803,11 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/flatpickr": { + "version": "4.6.9", + "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.9.tgz", + "integrity": "sha512-F0azNNi8foVWKSF+8X+ZJzz8r9sE1G4hl06RyceIaLvyltKvDl6vqk9Lm/6AUUCi5HWaIjiUbk7UpeE/fOXOpw==" + }, "node_modules/flatted": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", @@ -12794,6 +13006,12 @@ "url": "https://opencollective.com/immer" } }, + "node_modules/immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "peer": true + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -18240,6 +18458,16 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, + "node_modules/lodash.findlast": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.findlast/-/lodash.findlast-4.6.0.tgz", + "integrity": "sha512-+OGwb1FVKjhc2aIEQ9vKqNDW1a0/HaCLr0iCIK10jfVif3dBE0nhQD0jOZNZLh7zOlmFUTrk+vt85eXoH4vKuA==" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -18250,6 +18478,11 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, + "node_modules/lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==" + }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -18261,6 +18494,11 @@ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" + }, "node_modules/lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", @@ -23919,6 +24157,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, "node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -24247,6 +24490,23 @@ "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" }, + "node_modules/sass": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.55.0.tgz", + "integrity": "sha512-Pk+PMy7OGLs9WaxZGJMn7S96dvlyVBwwtToX895WmCpAOr5YiJYEUJfiJidMuKb613z2xNWcXCHEuOvjZbqC6A==", + "peer": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", @@ -24717,6 +24977,19 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -26202,6 +26475,11 @@ "ret": "~0.1.10" } }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -27747,6 +28025,18 @@ "react": "^16.8.0 || ^17.0.0" } }, + "node_modules/use-resize-observer": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-6.1.0.tgz", + "integrity": "sha512-SiPcWHiIQ1CnHmb6PxbYtygqiZXR0U9dNkkbpX9VYnlstUwF8+QqpUTrzh13pjPwcjMVGR+QIC+nvF5ujfFNng==", + "dependencies": { + "resize-observer-polyfill": "^1.5.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", @@ -28868,6 +29158,11 @@ "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", "dev": true }, + "node_modules/wicg-inert": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/wicg-inert/-/wicg-inert-3.1.2.tgz", + "integrity": "sha512-Ba9tGNYxXwaqKEi9sJJvPMKuo063umUPsHN0JJsjrs2j8KDSzkWLMZGZ+MH1Jf1Fq4OWZ5HsESJID6nRza2ang==" + }, "node_modules/widest-line": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", @@ -28923,6 +29218,11 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/window-or-global": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/window-or-global/-/window-or-global-1.0.1.tgz", + "integrity": "sha512-tE12J/NenOv4xdVobD+AD3fT06T4KNqnzRhkv5nBIu7K+pvOH2oLCEgYP+i+5mF2jtI6FEADheOdZkA8YWET9w==" + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -30836,6 +31136,124 @@ "resolved": "https://registry.npmjs.org/@camunda/zeebe-element-templates-json-schema/-/zeebe-element-templates-json-schema-0.6.0.tgz", "integrity": "sha512-qawIFM52lp1hW2vWrHaX8ywguZsp2olE0DRTHUY+KWH5GwszZwGWECP3tji1KVih2TasQyf28kcQVh8TeQ6dAg==" }, + "@carbon/colors": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/@carbon/colors/-/colors-11.7.0.tgz", + "integrity": "sha512-2B57vtirYTpxGg7p9yIO+s4cwL5QB8ogGQB5Pz+zdaHoVxrLsGlxAg28CQgk7yxw7doqST79bRVYS6FaJq+qJw==" + }, + "@carbon/feature-flags": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@carbon/feature-flags/-/feature-flags-0.9.0.tgz", + "integrity": "sha512-uNCRkxsNwLdJVNwQ5S5vrLAm4yawWzhFBwyP9EgXVmRzJH85Aim+miC+QNjRXntJDYhZYDuLABTeb3VD692ypA==" + }, + "@carbon/grid": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/@carbon/grid/-/grid-11.7.0.tgz", + "integrity": "sha512-OCDXQNSPVOoBQN08Qn5wo2WpKRGRm/kEBo6ZTl2NoDCl21mcYJZ0IDbKPTukixJB1sUNDUlnrpwMoaznPj48dw==", + "requires": { + "@carbon/layout": "^11.7.0" + } + }, + "@carbon/icon-helpers": { + "version": "10.34.0", + "resolved": "https://registry.npmjs.org/@carbon/icon-helpers/-/icon-helpers-10.34.0.tgz", + "integrity": "sha512-Ov9EBc1tR/DDrMI0pN1drj2jb27ISmYFBLdDji+aivVJkLPy8R/jikJOsOBgIq2kUjQJYNN199k2acHKjZdYIg==" + }, + "@carbon/icons-react": { + "version": "11.10.0", + "resolved": "https://registry.npmjs.org/@carbon/icons-react/-/icons-react-11.10.0.tgz", + "integrity": "sha512-807RWTfbvVzmsDg2DJ4FjwYNbJSgkrEd1Ui8I07YheJVb3sbYGGZMG7aCS0qXVlrQOhB2hggtxSW1w9NksUXNA==", + "requires": { + "@carbon/icon-helpers": "^10.34.0", + "@carbon/telemetry": "0.1.0", + "prop-types": "^15.7.2" + } + }, + "@carbon/layout": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/@carbon/layout/-/layout-11.7.0.tgz", + "integrity": "sha512-p4YQvW8U5Go0Tz1PZZgllGSPmoq8xBB5PHByuHiAjzwGclxPsBmY6Ea7tftINFW8VlcjDcampyT8VfZXhP2lFg==" + }, + "@carbon/motion": { + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/@carbon/motion/-/motion-11.5.0.tgz", + "integrity": "sha512-5QEALh+xZzICdgVLanSpiDfBTErzVgEze/xUKs7ZdSbd6p1FaDKDGvCmj9RCsaz/CMVHIWo65MshIglSWX5Xvw==" + }, + "@carbon/react": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@carbon/react/-/react-1.16.0.tgz", + "integrity": "sha512-kVeL/iyVqN2tfcoE1xliIm4w2ex9L4m/b8KuGo7ZuqBmRzANQdfSYGfj11KU0TXT1CbOVFrqsT/aBxApsP5IDg==", + "requires": { + "@babel/runtime": "^7.18.3", + "@carbon/feature-flags": "^0.9.0", + "@carbon/icons-react": "^11.10.0", + "@carbon/layout": "^11.7.0", + "@carbon/styles": "^1.16.0", + "@carbon/telemetry": "0.1.0", + "classnames": "2.3.2", + "copy-to-clipboard": "^3.3.1", + "downshift": "5.2.1", + "flatpickr": "4.6.9", + "invariant": "^2.2.3", + "lodash.debounce": "^4.0.8", + "lodash.findlast": "^4.5.0", + "lodash.isequal": "^4.5.0", + "lodash.omit": "^4.5.0", + "lodash.throttle": "^4.1.1", + "prop-types": "^15.7.2", + "react-is": "^17.0.2", + "use-resize-observer": "^6.0.0", + "wicg-inert": "^3.1.1", + "window-or-global": "^1.0.1" + }, + "dependencies": { + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + } + } + }, + "@carbon/styles": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@carbon/styles/-/styles-1.16.0.tgz", + "integrity": "sha512-LSjRw2Ws8rWI1a96KYUuX10jG+rpSn68dHlZhhDq+RJWsMGpjFhKUxPoTiJli2hHXyxey6rXV0hfr7oBJ0ud7w==", + "requires": { + "@carbon/colors": "^11.7.0", + "@carbon/feature-flags": "^0.9.0", + "@carbon/grid": "^11.7.0", + "@carbon/layout": "^11.7.0", + "@carbon/motion": "^11.5.0", + "@carbon/themes": "^11.11.0", + "@carbon/type": "^11.11.0", + "@ibm/plex": "6.0.0-next.6" + } + }, + "@carbon/telemetry": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@carbon/telemetry/-/telemetry-0.1.0.tgz", + "integrity": "sha512-kNWt0bkgPwGW0i5h7HFuljbKRXPvIhsKbB+1tEURAYLXoJg9iJLF1eGvWN5iVoFCS2zje4GR3OGOsvvKVe7Hlg==" + }, + "@carbon/themes": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@carbon/themes/-/themes-11.11.0.tgz", + "integrity": "sha512-EhLizr2oMqJXNubI2zWw09qcSPLZdWoBOQ6uNcjHzpXgoGNMwbVJE/qGMy/ivr+EOs6Fe0z5T0u97v+ZhSmRhg==", + "requires": { + "@carbon/colors": "^11.7.0", + "@carbon/layout": "^11.7.0", + "@carbon/type": "^11.11.0", + "color": "^4.0.0" + } + }, + "@carbon/type": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@carbon/type/-/type-11.11.0.tgz", + "integrity": "sha512-eX6z8BibP1En1xBm2wUd01Nzk0Tm1jftR2QSD4JBn4xhnkGR824gpcbLTAIMGx9/Mr3R65Enbam3uFO0OOaH8g==", + "requires": { + "@carbon/grid": "^11.7.0", + "@carbon/layout": "^11.7.0" + } + }, "@codemirror/autocomplete": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.3.0.tgz", @@ -31364,6 +31782,11 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" }, + "@ibm/plex": { + "version": "6.0.0-next.6", + "resolved": "https://registry.npmjs.org/@ibm/plex/-/plex-6.0.0-next.6.tgz", + "integrity": "sha512-B3uGruTn2rS5gweynLmfSe7yCawSRsJguJJQHVQiqf4rh2RNgJFu8YLE2Zd/JHV0ZXoVMOslcXP2k3hMkxKEyA==" + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -35236,9 +35659,9 @@ } }, "classnames": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", - "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" }, "clean-css": { "version": "5.3.1", @@ -35376,6 +35799,30 @@ "object-visit": "^1.0.0" } }, + "color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "requires": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "dependencies": { + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -35389,6 +35836,15 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", @@ -35614,6 +36070,14 @@ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==" }, + "copy-to-clipboard": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.2.tgz", + "integrity": "sha512-Vme1Z6RUDzrb6xAI7EZlVZ5uvOk2F//GaxKUxajDqm9LhOVM1inxNAD2vy+UZDYsd0uyA9s7b3/FVZPSxqrCfg==", + "requires": { + "toggle-selection": "^1.0.6" + } + }, "core_d": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/core_d/-/core_d-5.0.1.tgz", @@ -36020,9 +36484,9 @@ "integrity": "sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==" }, "cypress": { - "version": "10.8.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.8.0.tgz", - "integrity": "sha512-QVse0dnLm018hgti2enKMVZR9qbIO488YGX06nH5j3Dg1isL38DwrBtyrax02CANU6y8F4EJUuyW6HJKw1jsFA==", + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.11.0.tgz", + "integrity": "sha512-lsaE7dprw5DoXM00skni6W5ElVVLGAdRUUdZjX2dYsGjbY/QnpzWZ95Zom1mkGg0hAaO/QVTZoFVS7Jgr/GUPA==", "dev": true, "requires": { "@cypress/request": "^2.88.10", @@ -36715,6 +37179,24 @@ "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" }, + "downshift": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/downshift/-/downshift-5.2.1.tgz", + "integrity": "sha512-uHX2OLbWthLR8QbR8NCI8OmjvvJxq8+PrA95KblFd9JyB1zVZh1HnszzsWMMCnMuH6IvsUtVfF5HY7XfijJ2dw==", + "requires": { + "@babel/runtime": "^7.9.1", + "compute-scroll-into-view": "^1.0.13", + "prop-types": "^15.7.2", + "react-is": "^16.13.1" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, "duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -38020,6 +38502,11 @@ "rimraf": "^3.0.2" } }, + "flatpickr": { + "version": "4.6.9", + "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.9.tgz", + "integrity": "sha512-F0azNNi8foVWKSF+8X+ZJzz8r9sE1G4hl06RyceIaLvyltKvDl6vqk9Lm/6AUUCi5HWaIjiUbk7UpeE/fOXOpw==" + }, "flatted": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", @@ -38876,6 +39363,12 @@ "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.15.tgz", "integrity": "sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ==" }, + "immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "peer": true + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -43000,6 +43493,16 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, + "lodash.findlast": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.findlast/-/lodash.findlast-4.6.0.tgz", + "integrity": "sha512-+OGwb1FVKjhc2aIEQ9vKqNDW1a0/HaCLr0iCIK10jfVif3dBE0nhQD0jOZNZLh7zOlmFUTrk+vt85eXoH4vKuA==" + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -43010,6 +43513,11 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, + "lodash.omit": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-4.5.0.tgz", + "integrity": "sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==" + }, "lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", @@ -43021,6 +43529,11 @@ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" }, + "lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" + }, "lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", @@ -46934,6 +47447,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, + "resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, "resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -47167,6 +47685,17 @@ "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" }, + "sass": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.55.0.tgz", + "integrity": "sha512-Pk+PMy7OGLs9WaxZGJMn7S96dvlyVBwwtToX895WmCpAOr5YiJYEUJfiJidMuKb613z2xNWcXCHEuOvjZbqC6A==", + "peer": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", @@ -47565,6 +48094,21 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, "sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -48736,6 +49280,11 @@ "is-number": "^7.0.0" } }, + "toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==" + }, "toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -49905,6 +50454,14 @@ "integrity": "sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ==", "requires": {} }, + "use-resize-observer": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-6.1.0.tgz", + "integrity": "sha512-SiPcWHiIQ1CnHmb6PxbYtygqiZXR0U9dNkkbpX9VYnlstUwF8+QqpUTrzh13pjPwcjMVGR+QIC+nvF5ujfFNng==", + "requires": { + "resize-observer-polyfill": "^1.5.1" + } + }, "util": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", @@ -50782,6 +51339,11 @@ "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", "dev": true }, + "wicg-inert": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/wicg-inert/-/wicg-inert-3.1.2.tgz", + "integrity": "sha512-Ba9tGNYxXwaqKEi9sJJvPMKuo063umUPsHN0JJsjrs2j8KDSzkWLMZGZ+MH1Jf1Fq4OWZ5HsESJID6nRza2ang==" + }, "widest-line": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", @@ -50815,6 +51377,11 @@ } } }, + "window-or-global": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/window-or-global/-/window-or-global-1.0.1.tgz", + "integrity": "sha512-tE12J/NenOv4xdVobD+AD3fT06T4KNqnzRhkv5nBIu7K+pvOH2oLCEgYP+i+5mF2jtI6FEADheOdZkA8YWET9w==" + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", diff --git a/spiffworkflow-frontend/package.json b/spiffworkflow-frontend/package.json index e0a8b242..c9127d7c 100644 --- a/spiffworkflow-frontend/package.json +++ b/spiffworkflow-frontend/package.json @@ -6,6 +6,9 @@ "@babel/core": "^7.18.10", "@babel/plugin-transform-react-jsx": "^7.18.6", "@babel/preset-react": "^7.18.6", + "@carbon/icons-react": "^11.10.0", + "@carbon/react": "^1.16.0", + "@carbon/styles": "^1.16.0", "@ginkgo-bioworks/react-json-schema-form-builder": "^2.9.0", "@monaco-editor/react": "^4.4.5", "@rjsf/core": "^4.2.0", @@ -55,6 +58,10 @@ "@ginkgo-bioworks/react-json-schema-form-builder": { "react": "^18.2.0", "bootstrap": "^5.2.0-beta1" + }, + "@carbon/react": { + "react": "^18.2.0", + "react-dom": "^18.2.0" } }, "scripts": { diff --git a/spiffworkflow-frontend/src/App.tsx b/spiffworkflow-frontend/src/App.tsx index 0444f042..186ac513 100644 --- a/spiffworkflow-frontend/src/App.tsx +++ b/spiffworkflow-frontend/src/App.tsx @@ -1,5 +1,6 @@ import { useMemo, useState } from 'react'; -import { Container } from 'react-bootstrap'; +// @ts-ignore +import { Content } from '@carbon/react'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; import ErrorContext from './contexts/ErrorContext'; @@ -9,7 +10,6 @@ import HomePage from './routes/HomePage'; import TaskShow from './routes/TaskShow'; import ErrorBoundary from './components/ErrorBoundary'; import AdminRoutes from './routes/AdminRoutes'; -import SubNavigation from './components/SubNavigation'; import { ErrorForDisplay } from './interfaces'; export default function App() { @@ -47,30 +47,27 @@ export default function App() { return ( - - - {errorTag} - - - -
- - } /> - } /> - } /> - } - /> - } - /> - -
-
-
-
+ + + + {errorTag} + + + } /> + } /> + } /> + } + /> + } + /> + + + +
); } diff --git a/spiffworkflow-frontend/src/components/ButtonWithConfirmation.tsx b/spiffworkflow-frontend/src/components/ButtonWithConfirmation.tsx index 6956dadc..25aaadc1 100644 --- a/spiffworkflow-frontend/src/components/ButtonWithConfirmation.tsx +++ b/spiffworkflow-frontend/src/components/ButtonWithConfirmation.tsx @@ -1,5 +1,6 @@ import { useState } from 'react'; -import { Button, Modal } from 'react-bootstrap'; +// @ts-ignore +import { Button, Modal } from '@carbon/react'; type OwnProps = { description?: string; @@ -25,13 +26,6 @@ export default function ButtonWithConfirmation({ setShowConfirmationPrompt(false); }; - const modalBodyElement = () => { - if (description) { - return {description}; - } - return null; - }; - const handleConfirmation = () => { onConfirmation(); setShowConfirmationPrompt(false); @@ -40,28 +34,22 @@ export default function ButtonWithConfirmation({ const confirmationDialog = () => { return ( - - {title} - - {modalBodyElement()} - - - - - + open={showConfirmationPrompt} + danger + data-qa="modal-confirmation-dialog" + modalHeading={description} + modalLabel={title} + primaryButtonText={confirmButtonLabel} + secondaryButtonText="Cancel" + onSecondarySubmit={handleConfirmationPromptCancel} + onRequestSubmit={handleConfirmation} + /> ); }; return ( <> - {confirmationDialog()} diff --git a/spiffworkflow-frontend/src/components/NavigationBar.tsx b/spiffworkflow-frontend/src/components/NavigationBar.tsx index 9b070a55..30fcb70c 100644 --- a/spiffworkflow-frontend/src/components/NavigationBar.tsx +++ b/spiffworkflow-frontend/src/components/NavigationBar.tsx @@ -1,12 +1,28 @@ -import { Button, Navbar, Nav, Container } from 'react-bootstrap'; +import { + Header, + HeaderContainer, + HeaderMenuButton, + SkipToContent, + SideNav, + SideNavItems, + HeaderSideNavItems, + HeaderName, + HeaderNavigation, + HeaderMenuItem, + HeaderGlobalAction, + HeaderGlobalBar, + // @ts-ignore +} from '@carbon/react'; +// @ts-ignore +import { Logout, Login } from '@carbon/icons-react'; +import { useEffect, useState } from 'react'; +import { useLocation } from 'react-router-dom'; // @ts-expect-error TS(2307) FIXME: Cannot find module '../logo.svg' or its correspond... Remove this comment to see the full error message import logo from '../logo.svg'; import UserService from '../services/UserService'; // for ref: https://react-bootstrap.github.io/components/navbar/ export default function NavigationBar() { - const navElements = null; - const handleLogout = () => { UserService.doLogout(); }; @@ -15,56 +31,116 @@ export default function NavigationBar() { UserService.doLogin(); }; - const loginLink = () => { - if (!UserService.isLoggedIn()) { - return ( - - - - - - ); + const location = useLocation(); + const [activeKey, setActiveKey] = useState(''); + + useEffect(() => { + let newActiveKey = '/admin/process-groups'; + if (location.pathname.match(/^\/admin\/messages\b/)) { + newActiveKey = '/admin/messages'; + } else if (location.pathname.match(/^\/admin\/process-instances\b/)) { + newActiveKey = '/admin/process-instances'; + } else if (location.pathname.match(/^\/admin\/secrets\b/)) { + newActiveKey = '/admin/secrets'; + } else if (location.pathname.match(/^\/admin\/authentications\b/)) { + newActiveKey = '/admin/authentications'; + } else if (location.pathname === '/') { + newActiveKey = '/'; + } else if (location.pathname.match(/^\/tasks\b/)) { + newActiveKey = '/'; } - return null; + setActiveKey(newActiveKey); + }, [location]); + + const isActivePage = (menuItemPath: string) => { + return activeKey === menuItemPath; }; - const logoutLink = () => { + const loginAndLogoutAction = () => { if (UserService.isLoggedIn()) { return ( - - - Signed in as: {UserService.getUsername()} - - - - - + <> + {UserService.getUsername()} + + + + ); } - return null; + return ( + + + + ); }; - return ( - - - - logo - - - - - - {loginLink()} - {logoutLink()} - - - ); + const headerMenuItems = () => { + return ( + <> + + Home + + + Processes + + + Process Instances + + + ); + }; + + if (activeKey) { + // TODO: apply theme g100 to the header + return ( + ( +
+ + + + logo + + + {headerMenuItems()} + + + + {headerMenuItems()} + + + {loginAndLogoutAction()} +
+ )} + /> + ); + } + return null; } diff --git a/spiffworkflow-frontend/src/components/PaginationForTable.tsx b/spiffworkflow-frontend/src/components/PaginationForTable.tsx index 2f648f52..3b65c78c 100644 --- a/spiffworkflow-frontend/src/components/PaginationForTable.tsx +++ b/spiffworkflow-frontend/src/components/PaginationForTable.tsx @@ -1,7 +1,8 @@ -import React from 'react'; -import { Link } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; -import { Dropdown, Stack } from 'react-bootstrap'; +// @ts-ignore +import { Pagination } from '@carbon/react'; +import { PaginationObject } from '../interfaces'; export const DEFAULT_PER_PAGE = 50; export const DEFAULT_PAGE = 1; @@ -10,9 +11,7 @@ type OwnProps = { page: number; perPage: number; perPageOptions?: number[]; - pagination: { - [key: string]: number; - }; + pagination: PaginationObject | null; tableToDisplay: any; queryParamString?: string; path: string; @@ -28,140 +27,32 @@ export default function PaginationForTable({ path, }: OwnProps) { const PER_PAGE_OPTIONS = [2, 10, 50, 100]; + const navigate = useNavigate(); - const buildPerPageDropdown = () => { - const perPageDropdownRows = (perPageOptions || PER_PAGE_OPTIONS).map( - (perPageOption) => { - if (perPageOption === perPage) { - return ( - - {perPageOption} - - ); - } - return ( - - {perPageOption} - - ); - } - ); - return ( - - - - Number to show: {perPage} - - - {perPageDropdownRows} - - - ); + const updateRows = (args: any) => { + const newPage = args.page; + const { pageSize } = args; + navigate(`${path}?page=${newPage}&per_page=${pageSize}${queryParamString}`); }; - const buildPaginationNav = () => { - let previousPageTag = null; - if (page === 1) { - previousPageTag = ( -
  • - - « - -
  • - ); - } else { - previousPageTag = ( -
  • - - « - -
  • - ); - } - - let nextPageTag = null; - if (page >= pagination.pages) { - nextPageTag = ( -
  • - - » - -
  • - ); - } else { - nextPageTag = ( -
  • - - » - -
  • - ); - } - - let startingNumber = (page - 1) * perPage + 1; - let endingNumber = page * perPage; - if (endingNumber > pagination.total) { - endingNumber = pagination.total; - } - if (startingNumber > pagination.total) { - startingNumber = pagination.total; - } - + if (pagination) { return ( - -

    - {startingNumber}-{endingNumber} of{' '} - {pagination.total} -

    - -
    + <> + {tableToDisplay} + + ); - }; - - return ( -
    - {buildPaginationNav()} - {tableToDisplay} - {buildPerPageDropdown()} -
    - ); + } + return null; } diff --git a/spiffworkflow-frontend/src/components/ProcessGroupForm.tsx b/spiffworkflow-frontend/src/components/ProcessGroupForm.tsx new file mode 100644 index 00000000..128a13c0 --- /dev/null +++ b/spiffworkflow-frontend/src/components/ProcessGroupForm.tsx @@ -0,0 +1,181 @@ +import { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +// @ts-ignore +import { Button, ButtonSet, Form, Stack, TextInput } from '@carbon/react'; +import { slugifyString } from '../helpers'; +import HttpService from '../services/HttpService'; +import { ProcessGroup } from '../interfaces'; +import ButtonWithConfirmation from './ButtonWithConfirmation'; + +type OwnProps = { + mode: string; + processGroup: ProcessGroup; + setProcessGroup: (..._args: any[]) => any; +}; + +export default function ProcessGroupForm({ + mode, + processGroup, + setProcessGroup, +}: OwnProps) { + const [identifierInvalid, setIdentifierInvalid] = useState(false); + const [idHasBeenUpdatedByUser, setIdHasBeenUpdatedByUser] = + useState(false); + const [displayNameInvalid, setDisplayNameInvalid] = useState(false); + const navigate = useNavigate(); + + const navigateToProcessGroup = (_result: any) => { + if (processGroup) { + navigate(`/admin/process-groups/${processGroup.id}`); + } + }; + + const navigateToProcessGroups = (_result: any) => { + navigate(`/admin/process-groups`); + }; + + const hasValidIdentifier = (identifierToCheck: string) => { + return identifierToCheck.match(/^[a-z0-9][0-9a-z-]+[a-z0-9]$/); + }; + + const deleteProcessGroup = () => { + HttpService.makeCallToBackend({ + path: `/process-groups/${processGroup.id}`, + successCallback: navigateToProcessGroups, + httpMethod: 'DELETE', + }); + }; + + const handleFormSubmission = (event: any) => { + event.preventDefault(); + let hasErrors = false; + if (!hasValidIdentifier(processGroup.id)) { + setIdentifierInvalid(true); + hasErrors = true; + } + if (processGroup.display_name === '') { + setDisplayNameInvalid(true); + hasErrors = true; + } + if (hasErrors) { + return; + } + let path = '/process-groups'; + if (mode === 'edit') { + path = `/process-groups/${processGroup.id}`; + } + let httpMethod = 'POST'; + if (mode === 'edit') { + httpMethod = 'PUT'; + } + const postBody = { + display_name: processGroup.display_name, + description: processGroup.description, + }; + if (mode === 'new') { + Object.assign(postBody, { id: processGroup.id }); + } + + HttpService.makeCallToBackend({ + path, + successCallback: navigateToProcessGroup, + httpMethod, + postBody, + }); + }; + + const updateProcessGroup = (newValues: any) => { + const processGroupToCopy = { + ...processGroup, + }; + Object.assign(processGroupToCopy, newValues); + setProcessGroup(processGroupToCopy); + }; + + const onDisplayNameChanged = (newDisplayName: any) => { + setDisplayNameInvalid(false); + const updateDict = { display_name: newDisplayName }; + if (!idHasBeenUpdatedByUser) { + Object.assign(updateDict, { id: slugifyString(newDisplayName) }); + } + updateProcessGroup(updateDict); + }; + + const formElements = () => { + const textInputs = [ + onDisplayNameChanged(event.target.value)} + onBlur={(event: any) => console.log('event', event)} + />, + ]; + + if (mode === 'new') { + textInputs.push( + { + updateProcessGroup({ id: event.target.value }); + // was invalid, and now valid + if (identifierInvalid && hasValidIdentifier(event.target.value)) { + setIdentifierInvalid(false); + } + setIdHasBeenUpdatedByUser(true); + }} + /> + ); + } + + textInputs.push( + + updateProcessGroup({ description: event.target.value }) + } + /> + ); + + return textInputs; + }; + + const formButtons = () => { + const buttons = [ + , + ]; + if (mode === 'edit') { + buttons.push( + + ); + } + return {buttons}; + }; + + return ( +
    + + {formElements()} + {formButtons()} + +
    + ); +} diff --git a/spiffworkflow-frontend/src/components/ProcessModelSearch.tsx b/spiffworkflow-frontend/src/components/ProcessModelSearch.tsx new file mode 100644 index 00000000..98419d6c --- /dev/null +++ b/spiffworkflow-frontend/src/components/ProcessModelSearch.tsx @@ -0,0 +1,48 @@ +import { + ComboBox, + // @ts-ignore +} from '@carbon/react'; +import { truncateString } from '../helpers'; +import { ProcessModel } from '../interfaces'; + +type OwnProps = { + onChange: (..._args: any[]) => any; + processModels: ProcessModel[]; + selectedItem?: ProcessModel | null; + titleText?: string; +}; + +export default function ProcessModelSearch({ + processModels, + selectedItem, + onChange, + titleText = 'Process model', +}: OwnProps) { + const shouldFilterProcessModel = (options: any) => { + const processModel: ProcessModel = options.item; + const { inputValue } = options; + return `${processModel.process_group_id}/${processModel.id} (${processModel.display_name})`.includes( + inputValue + ); + }; + return ( + { + if (processModel) { + return `${processModel.process_group_id}/${ + processModel.id + } (${truncateString(processModel.display_name, 20)})`; + } + return null; + }} + shouldFilterItem={shouldFilterProcessModel} + placeholder="Choose a process model" + titleText={titleText} + selectedItem={selectedItem} + /> + ); +} diff --git a/spiffworkflow-frontend/src/components/ReactDiagramEditor.tsx b/spiffworkflow-frontend/src/components/ReactDiagramEditor.tsx index 9728e7d5..2bbf64db 100644 --- a/spiffworkflow-frontend/src/components/ReactDiagramEditor.tsx +++ b/spiffworkflow-frontend/src/components/ReactDiagramEditor.tsx @@ -18,7 +18,8 @@ import { } from 'dmn-js-properties-panel'; import React, { useRef, useEffect, useState } from 'react'; -import Button from 'react-bootstrap/Button'; +// @ts-ignore +import { Button } from '@carbon/react'; import 'bpmn-js/dist/assets/diagram-js.css'; import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'; diff --git a/spiffworkflow-frontend/src/config.tsx b/spiffworkflow-frontend/src/config.tsx index 94519ba8..c9e94eb0 100644 --- a/spiffworkflow-frontend/src/config.tsx +++ b/spiffworkflow-frontend/src/config.tsx @@ -16,4 +16,6 @@ export const PROCESS_STATUSES = [ 'suspended', ]; -export const DATE_FORMAT = 'yyyy-MM-dd HH:mm:ss'; +// with time: yyyy-MM-dd HH:mm:ss +export const DATE_FORMAT = 'yyyy-MM-dd'; +export const DATE_FORMAT_CARBON = 'Y-m-d'; diff --git a/spiffworkflow-frontend/src/helpers.tsx b/spiffworkflow-frontend/src/helpers.tsx index 59922acf..6b27fb4c 100644 --- a/spiffworkflow-frontend/src/helpers.tsx +++ b/spiffworkflow-frontend/src/helpers.tsx @@ -20,7 +20,10 @@ export const capitalizeFirstLetter = (string: any) => { return string.charAt(0).toUpperCase() + string.slice(1); }; -export const convertDateToSeconds = (date: any, onChangeFunction: any) => { +export const convertDateToSeconds = ( + date: any, + onChangeFunction: any = null +) => { let dateInSeconds = date; if (date !== null) { let dateInMilliseconds = date; @@ -39,14 +42,26 @@ export const convertDateToSeconds = (date: any, onChangeFunction: any) => { return null; }; -export const convertSecondsToFormattedDate = (seconds: number) => { - if (seconds) { - const startDate = new Date(seconds * 1000); - return format(startDate, DATE_FORMAT); +export const convertStringToDate = (dateString: string) => { + if (dateString) { + return new Date(dateString); } return null; }; +export const convertSecondsToFormattedDate = (seconds: number) => { + if (seconds) { + const dateObject = new Date(seconds * 1000); + return format(dateObject, DATE_FORMAT); + } + return null; +}; + +export const convertDateStringToSeconds = (dateString: string) => { + const dateObject = convertStringToDate(dateString); + return convertDateToSeconds(dateObject); +}; + export const objectIsEmpty = (obj: object) => { return Object.keys(obj).length === 0; }; @@ -90,3 +105,11 @@ export const getProcessModelFullIdentifierFromSearchParams = ( } return processModelFullIdentifier; }; + +// https://stackoverflow.com/a/71352046/6090676 +export const truncateString = (text: string, len: number) => { + if (text.length > len && text.length > 0) { + return `${text.split(' ').slice(0, len).join(' ')} ...`; + } + return text; +}; diff --git a/spiffworkflow-frontend/src/index.css b/spiffworkflow-frontend/src/index.css index fd156c23..988fae27 100644 --- a/spiffworkflow-frontend/src/index.css +++ b/spiffworkflow-frontend/src/index.css @@ -20,12 +20,15 @@ span.bjs-crumb { } .app-logo { - height: 35%; - width: 35%; + height: 85%; + width: 85%; margin-top: 1em; margin-bottom: 1em; } +.spiffworkflow-header-container { + margin-bottom: 2em; +} .active-task-highlight:not(.djs-connection) .djs-visual > :nth-child(1) { fill: yellow !important; @@ -44,6 +47,17 @@ span.bjs-crumb { margin:auto; } +.cds--btn.button-white-background { + color: #393939; + background: #FFFFFF; + background-blend-mode: multiply; + border: 1px solid #393939; +} + +.with-bottom-margin { + margin-bottom: 1em; +} + .diagram-viewer-canvas { border:1px solid #000000; height:70vh; diff --git a/spiffworkflow-frontend/src/index.scss b/spiffworkflow-frontend/src/index.scss new file mode 100644 index 00000000..b4c90da1 --- /dev/null +++ b/spiffworkflow-frontend/src/index.scss @@ -0,0 +1,5 @@ +// @use '@carbon/react/scss/themes'; +// @use '@carbon/react/scss/theme' with ($theme: themes.$g100); +@use '@carbon/react'; +@use '@carbon/styles'; +// @include grid.flex-grid(); diff --git a/spiffworkflow-frontend/src/index.tsx b/spiffworkflow-frontend/src/index.tsx index ebd40415..a2fab5c0 100644 --- a/spiffworkflow-frontend/src/index.tsx +++ b/spiffworkflow-frontend/src/index.tsx @@ -4,6 +4,7 @@ import App from './App'; import 'bootstrap/dist/css/bootstrap.css'; import './index.css'; +import './index.scss'; import reportWebVitals from './reportWebVitals'; import UserService from './services/UserService'; diff --git a/spiffworkflow-frontend/src/interfaces.ts b/spiffworkflow-frontend/src/interfaces.ts index 8e153c80..14ead3ba 100644 --- a/spiffworkflow-frontend/src/interfaces.ts +++ b/spiffworkflow-frontend/src/interfaces.ts @@ -14,6 +14,7 @@ export interface RecentProcessModel { export interface ProcessGroup { id: string; display_name: string; + description?: string | null; } export interface ProcessModel { @@ -41,3 +42,13 @@ export interface AuthenticationItem { id: string; parameters: AuthenticationParam[]; } + +export interface PaginationObject { + count: number; + total: number; + pages: number; +} + +export interface CarbonComboBoxSelection { + selectedItem: ProcessModel; +} diff --git a/spiffworkflow-frontend/src/routes/AuthenticationList.tsx b/spiffworkflow-frontend/src/routes/AuthenticationList.tsx index 6be0f054..a249aa27 100644 --- a/spiffworkflow-frontend/src/routes/AuthenticationList.tsx +++ b/spiffworkflow-frontend/src/routes/AuthenticationList.tsx @@ -1,5 +1,6 @@ import { useContext, useEffect, useState } from 'react'; -import { Table } from 'react-bootstrap'; +// @ts-ignore +import { Table } from '@carbon/react'; import ErrorContext from '../contexts/ErrorContext'; import { AuthenticationItem } from '../interfaces'; import HttpService from '../services/HttpService'; diff --git a/spiffworkflow-frontend/src/routes/HomePage.tsx b/spiffworkflow-frontend/src/routes/HomePage.tsx index 4d348ed2..2cfc0078 100644 --- a/spiffworkflow-frontend/src/routes/HomePage.tsx +++ b/spiffworkflow-frontend/src/routes/HomePage.tsx @@ -1,17 +1,18 @@ import { useEffect, useState } from 'react'; -import { Button, Table } from 'react-bootstrap'; +// @ts-ignore +import { Button, Table } from '@carbon/react'; import { Link, useSearchParams } from 'react-router-dom'; import PaginationForTable from '../components/PaginationForTable'; import { getPageInfoFromSearchParams } from '../helpers'; import HttpService from '../services/HttpService'; -import { RecentProcessModel } from '../interfaces'; +import { PaginationObject, RecentProcessModel } from '../interfaces'; const PER_PAGE_FOR_TASKS_ON_HOME_PAGE = 5; export default function HomePage() { const [searchParams] = useSearchParams(); const [tasks, setTasks] = useState([]); - const [pagination, setPagination] = useState(null); + const [pagination, setPagination] = useState(null); useEffect(() => { const { page, perPage } = getPageInfoFromSearchParams( @@ -53,7 +54,7 @@ export default function HomePage() { data-qa="process-instance-show-link" to={`/admin/process-models/${rowToUse.process_group_identifier}/${rowToUse.process_model_identifier}/process-instances/${rowToUse.process_instance_id}`} > - View + View {rowToUse.process_instance_id} 0 && buildRecentProcessModelSection(); - - if (pagination) { + const tasksWaitingForMeComponent = () => { + if (pagination && pagination.total < 1) { + return null; + } const { page, perPage } = getPageInfoFromSearchParams( searchParams, PER_PAGE_FOR_TASKS_ON_HOME_PAGE @@ -144,6 +145,17 @@ export default function HomePage() { tableToDisplay={buildTable()} path="/tasks" /> + + ); + }; + + const relevantProcessModelSection = + recentProcessModels.length > 0 && buildRecentProcessModelSection(); + + if (pagination) { + return ( + <> + {tasksWaitingForMeComponent()} {relevantProcessModelSection} ); diff --git a/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx b/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx index 90c74c29..6bc0a57d 100644 --- a/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx +++ b/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx @@ -1,5 +1,6 @@ import { useEffect, useState } from 'react'; -import { Table } from 'react-bootstrap'; +// @ts-ignore +import { Table } from '@carbon/react'; import { Link, useParams, useSearchParams } from 'react-router-dom'; import PaginationForTable from '../components/PaginationForTable'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; diff --git a/spiffworkflow-frontend/src/routes/ProcessGroupEdit.tsx b/spiffworkflow-frontend/src/routes/ProcessGroupEdit.tsx index 83379999..d624309c 100644 --- a/spiffworkflow-frontend/src/routes/ProcessGroupEdit.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessGroupEdit.tsx @@ -1,20 +1,18 @@ import { useState, useEffect } from 'react'; -import { useParams, useNavigate } from 'react-router-dom'; -import { Button, Stack } from 'react-bootstrap'; +import { useParams } from 'react-router-dom'; +// @ts-ignore import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import HttpService from '../services/HttpService'; -import ButtonWithConfirmation from '../components/ButtonWithConfirmation'; +import ProcessGroupForm from '../components/ProcessGroupForm'; +import { ProcessGroup } from '../interfaces'; export default function ProcessGroupEdit() { - const [displayName, setDisplayName] = useState(''); const params = useParams(); - const navigate = useNavigate(); - const [processGroup, setProcessGroup] = useState(null); + const [processGroup, setProcessGroup] = useState(null); useEffect(() => { const setProcessGroupsFromResult = (result: any) => { setProcessGroup(result); - setDisplayName(result.display_name); }; HttpService.makeCallToBackend({ @@ -23,69 +21,16 @@ export default function ProcessGroupEdit() { }); }, [params]); - const navigateToProcessGroup = (_result: any) => { - navigate(`/admin/process-groups/${(processGroup as any).id}`); - }; - - const navigateToProcessGroups = (_result: any) => { - navigate(`/admin/process-groups`); - }; - - const updateProcessGroup = (event: any) => { - event.preventDefault(); - HttpService.makeCallToBackend({ - path: `/process-groups/${(processGroup as any).id}`, - successCallback: navigateToProcessGroup, - httpMethod: 'PUT', - postBody: { - display_name: displayName, - id: (processGroup as any).id, - }, - }); - }; - - const deleteProcessGroup = () => { - HttpService.makeCallToBackend({ - path: `/process-groups/${(processGroup as any).id}`, - successCallback: navigateToProcessGroups, - httpMethod: 'DELETE', - }); - }; - - const onDisplayNameChanged = (newDisplayName: any) => { - setDisplayName(newDisplayName); - }; - if (processGroup) { return ( <>

    Edit Process Group: {(processGroup as any).id}

    -
    - - onDisplayNameChanged(e.target.value)} - /> -
    -
    - - - - - -
    + ); } diff --git a/spiffworkflow-frontend/src/routes/ProcessGroupList.tsx b/spiffworkflow-frontend/src/routes/ProcessGroupList.tsx index 3c1be15c..13f3d455 100644 --- a/spiffworkflow-frontend/src/routes/ProcessGroupList.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessGroupList.tsx @@ -1,13 +1,21 @@ import { useEffect, useState } from 'react'; import { Link, useNavigate, useSearchParams } from 'react-router-dom'; -import { Button, Form, InputGroup, Table } from 'react-bootstrap'; -import { Typeahead } from 'react-bootstrap-typeahead'; -import { Option } from 'react-bootstrap-typeahead/types/types'; +import { + Button, + Table, + // ExpandableTile, + // TileAboveTheFoldContent, + // TileBelowTheFoldContent, + // TextInput, + // ClickableTile, + // @ts-ignore +} from '@carbon/react'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import PaginationForTable from '../components/PaginationForTable'; import HttpService from '../services/HttpService'; import { getPageInfoFromSearchParams } from '../helpers'; -import { ProcessModel } from '../interfaces'; +import { CarbonComboBoxSelection, ProcessGroup } from '../interfaces'; +import ProcessModelSearch from '../components/ProcessModelSearch'; // Example process group json // {'process_group_id': 'sure', 'display_name': 'Test Workflows', 'id': 'test_process_group'} @@ -17,8 +25,9 @@ export default function ProcessGroupList() { const [processGroups, setProcessGroups] = useState([]); const [pagination, setPagination] = useState(null); - const [processModeleSelectionOptions, setProcessModelSelectionOptions] = - useState([]); + const [processModelAvailableItems, setProcessModelAvailableItems] = useState( + [] + ); useEffect(() => { const setProcessGroupsFromResult = (result: any) => { @@ -31,7 +40,7 @@ export default function ProcessGroupList() { Object.assign(item, { label }); return item; }); - setProcessModelSelectionOptions(selectionArray); + setProcessModelAvailableItems(selectionArray); }; const { page, perPage } = getPageInfoFromSearchParams(searchParams); @@ -48,7 +57,7 @@ export default function ProcessGroupList() { }, [searchParams]); const buildTable = () => { - const rows = processGroups.map((row) => { + const rows = processGroups.map((row: ProcessGroup) => { return ( @@ -72,6 +81,17 @@ export default function ProcessGroupList() { {rows} ); + // const rows = processGroups.map((row: ProcessGroup) => { + // return ( + // + // + // {row.display_name} + // + // + // ); + // }); + // + // return
    {rows}
    ; }; const processGroupsDisplayArea = () => { @@ -97,35 +117,18 @@ export default function ProcessGroupList() { }; const processModelSearchArea = () => { - const processModelSearchOnChange = (selected: Option[]) => { - const processModel = selected[0] as ProcessModel; + const processModelSearchOnChange = (selection: CarbonComboBoxSelection) => { + const processModel = selection.selectedItem; navigate( `/admin/process-models/${processModel.process_group_id}/${processModel.id}` ); }; return ( -
    -

    Search

    - - - - Process Model:{' '} - - - - -
    + ); }; @@ -133,7 +136,9 @@ export default function ProcessGroupList() { return ( <> - +

    {processModelSearchArea()} diff --git a/spiffworkflow-frontend/src/routes/ProcessGroupNew.tsx b/spiffworkflow-frontend/src/routes/ProcessGroupNew.tsx index 2f3f3a35..d4d8b038 100644 --- a/spiffworkflow-frontend/src/routes/ProcessGroupNew.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessGroupNew.tsx @@ -1,71 +1,24 @@ import { useState } from 'react'; -import { useNavigate } from 'react-router-dom'; -import Button from 'react-bootstrap/Button'; -import Form from 'react-bootstrap/Form'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; -import { slugifyString } from '../helpers'; -import HttpService from '../services/HttpService'; +import ProcessGroupForm from '../components/ProcessGroupForm'; +import { ProcessGroup } from '../interfaces'; export default function ProcessGroupNew() { - const [identifier, setIdentifier] = useState(''); - const [idHasBeenUpdatedByUser, setIdHasBeenUpdatedByUser] = useState(false); - const [displayName, setDisplayName] = useState(''); - const navigate = useNavigate(); - - const navigateToProcessGroup = (_result: any) => { - navigate(`/admin/process-groups/${identifier}`); - }; - - const addProcessGroup = (event: any) => { - event.preventDefault(); - HttpService.makeCallToBackend({ - path: `/process-groups`, - successCallback: navigateToProcessGroup, - httpMethod: 'POST', - postBody: { - id: identifier, - display_name: displayName, - }, - }); - }; - - const onDisplayNameChanged = (newDisplayName: any) => { - setDisplayName(newDisplayName); - if (!idHasBeenUpdatedByUser) { - setIdentifier(slugifyString(newDisplayName)); - } - }; + const [processGroup, setProcessGroup] = useState({ + id: '', + display_name: '', + description: '', + }); return ( <>

    Add Process Group

    -
    - - Display Name: - onDisplayNameChanged(e.target.value)} - /> - - - ID: - { - setIdentifier(e.target.value); - setIdHasBeenUpdatedByUser(true); - }} - /> - - -
    + ); } diff --git a/spiffworkflow-frontend/src/routes/ProcessGroupShow.tsx b/spiffworkflow-frontend/src/routes/ProcessGroupShow.tsx index 522058c3..25e58044 100644 --- a/spiffworkflow-frontend/src/routes/ProcessGroupShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessGroupShow.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react'; import { Link, useSearchParams, useParams } from 'react-router-dom'; -import { Button, Table, Stack } from 'react-bootstrap'; +// @ts-ignore +import { Button, Table, Stack } from '@carbon/react'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import PaginationForTable from '../components/PaginationForTable'; import HttpService from '../services/HttpService'; @@ -81,7 +82,7 @@ export default function ProcessGroupShow() { ]} />
      - + - - - -
      -
      - + <> + + + + setProcessModelSelection(selection.selectedItem) + } + processModels={processModelAvailableItems} + selectedItem={processModelSelection} + /> + + {processStatusSearch()} + + + + {dateComponent( + 'Start date from', + 'start-from', + startFrom, + setStartFrom + )} + + + {dateComponent('Start date to', 'start-to', startTo, setStartTo)} + + + {dateComponent('End date from', 'end-from', endFrom, setEndFrom)} + + + {dateComponent('End date to', 'end-to', endTo, setEndTo)} + + + + + + + + + + + ); }; @@ -404,7 +415,7 @@ export default function ProcessInstanceList() { ); }); return ( - +
      @@ -436,20 +447,42 @@ export default function ProcessInstanceList() { ); }; + const toggleShowFilterOptions = () => { + setShowFilterOptions(!showFilterOptions); + }; + if (pagination) { const { page, perPage } = getPageInfoFromSearchParams(searchParams); return ( <> {processInstanceTitleElement()} + + + + - - - + + + + setNewFileName(e.target.value)} + autoFocus + /> + {fileExtension} + ); }; @@ -288,7 +283,6 @@ export default function ProcessModelEditDiagram() { // we should update this to act like updating scripts // where we pass an event to bpmn-js setScriptModeling(modeling); - setScriptText(script || ''); setScriptType(scriptTypeString); setScriptEventBus(eventBus); @@ -478,7 +472,7 @@ export default function ProcessModelEditDiagram() { } return (
      - +
      {scriptUnitTestResultBoolElement} - - + + {unitTestFailureElement()} - +
      Input Json:
      @@ -564,28 +558,25 @@ export default function ProcessModelEditDiagram() { if (scriptElement) { scriptName = (scriptElement as any).di.bpmnElement.name; } + return ( - - - Editing Script: {scriptName} - - - - {scriptUnitTestEditorElement()} - - - - + + + {scriptUnitTestEditorElement()} ); }; diff --git a/spiffworkflow-frontend/src/routes/ProcessModelShow.tsx b/spiffworkflow-frontend/src/routes/ProcessModelShow.tsx index 63217d2d..30f81e6d 100644 --- a/spiffworkflow-frontend/src/routes/ProcessModelShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessModelShow.tsx @@ -1,6 +1,7 @@ import { useContext, useEffect, useState } from 'react'; import { Link, useParams } from 'react-router-dom'; -import { Button, Stack } from 'react-bootstrap'; +// @ts-ignore +import { Button, Stack } from '@carbon/react'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import FileInput from '../components/FileInput'; import HttpService from '../services/HttpService'; @@ -210,7 +211,7 @@ export default function ProcessModelShow() { const processModelButtons = () => { return ( - + diff --git a/spiffworkflow-frontend/src/routes/ReactFormEditor.tsx b/spiffworkflow-frontend/src/routes/ReactFormEditor.tsx index 40dd2d89..e706a3ef 100644 --- a/spiffworkflow-frontend/src/routes/ReactFormEditor.tsx +++ b/spiffworkflow-frontend/src/routes/ReactFormEditor.tsx @@ -1,7 +1,8 @@ import { useEffect, useState } from 'react'; import Editor from '@monaco-editor/react'; import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; -import { Button, Modal } from 'react-bootstrap'; +// @ts-ignore +import { Button, Modal } from '@carbon/react'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import HttpService from '../services/HttpService'; import ButtonWithConfirmation from '../components/ButtonWithConfirmation'; @@ -118,31 +119,25 @@ export default function ReactFormEditor() { const newFileNameBox = () => { return ( - - - Process Model File Name - -
      - - - setNewFileName(e.target.value)} - autoFocus - /> - .{fileExtension} - - - - - - + + + + setNewFileName(e.target.value)} + autoFocus + /> + {fileExtension} + ); }; @@ -160,7 +155,7 @@ export default function ReactFormEditor() { {processModelFile ? `: ${(processModelFile as any).name}` : ''} {newFileNameBox()} - {params.file_name ? ( diff --git a/spiffworkflow-frontend/src/routes/SecretList.tsx b/spiffworkflow-frontend/src/routes/SecretList.tsx index 2b9e756a..7d165c01 100644 --- a/spiffworkflow-frontend/src/routes/SecretList.tsx +++ b/spiffworkflow-frontend/src/routes/SecretList.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react'; import { Link, useSearchParams } from 'react-router-dom'; -import { Button, Table } from 'react-bootstrap'; +// @ts-ignore +import { Button, Table } from '@carbon/react'; import { MdDelete } from 'react-icons/md'; import PaginationForTable from '../components/PaginationForTable'; import HttpService from '../services/HttpService'; diff --git a/spiffworkflow-frontend/src/routes/SecretNew.tsx b/spiffworkflow-frontend/src/routes/SecretNew.tsx index 7a697a98..016fec2e 100644 --- a/spiffworkflow-frontend/src/routes/SecretNew.tsx +++ b/spiffworkflow-frontend/src/routes/SecretNew.tsx @@ -1,6 +1,7 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { Stack } from 'react-bootstrap'; +// @ts-ignore +import { Stack } from '@carbon/react'; import Button from 'react-bootstrap/Button'; import Form from 'react-bootstrap/Form'; import HttpService from '../services/HttpService'; @@ -67,7 +68,7 @@ export default function SecretNew() { }} /> - + diff --git a/spiffworkflow-frontend/src/routes/SecretShow.tsx b/spiffworkflow-frontend/src/routes/SecretShow.tsx index 707f0d14..9882247b 100644 --- a/spiffworkflow-frontend/src/routes/SecretShow.tsx +++ b/spiffworkflow-frontend/src/routes/SecretShow.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; -import { Stack, Table, Button } from 'react-bootstrap'; +// @ts-ignore +import { Stack, Table, Button } from '@carbon/react'; import HttpService from '../services/HttpService'; import { Secret } from '../interfaces'; import ButtonWithConfirmation from '../components/ButtonWithConfirmation'; @@ -64,8 +65,8 @@ export default function SecretShow() { if (secret) { return ( <> - -

      Secret Key: {secret.key}

      +

      Secret Key: {secret.key}

      + + {userTasksElement}
      Process Instance Id