diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index 5fc356d487..0000000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "Fidesctl", - "dockerComposeFile": "../docker-compose.yml", - "service": "fidesctl", - "workspaceFolder": "/fides", - "shutdownAction": "stopCompose", - "extensions": [ - "ms-python.python", - "ms-azuretools.vscode-docker", - "redhat.vscode-yaml", - "davidanson.vscode-markdownlint", - "bungcip.better-toml", - "github.vscode-pull-request-github", - "ms-python.vscode-pylance", - "ethyca.fidesctl" - ], - "settings": { - "editor.formatOnSave": true, - "editor.tabSize": 4, - "editor.insertSpaces": true, - "python.formatting.provider": "black", - "python.linting.mypyEnabled": true, - "conf.fidesctl.confFilePath": "/fides/.fides/fidesctl.toml", - "conf.fidesctl.manifestFilePath": "/fides/.fides/", - "conf.fidesctl.parseOnSave": true - } -} diff --git a/.dockerignore b/.dockerignore index efd8ddfd46..3d118b23e0 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,8 +1,14 @@ # Ignore existing build artifacts build/ dist/ -src/fidesctl.egg-info/ -src/fidesctl/ui-build/ +src/fides.egg-info/ +src/fides/ui-build/ +src/ui-build/ + +# Frontend +**/node_modules +**/.next + # Ignore Python-Specific Files .mypy_cache/ @@ -10,6 +16,9 @@ src/fidesctl/ui-build/ .pytest_cache/ __pycache__/ .coverage +**.*.pyc +**.*.pyo +**.*.pyd # pyenv .python-version @@ -30,8 +39,8 @@ docs/ # Ignore dev files .github/ .devcontainer/ -**/node_modules/ # Ignore cypress artifacts **/videos/ **/screenshots/ +.DS_Store diff --git a/.fides/celery.toml b/.fides/celery.toml new file mode 100644 index 0000000000..71e19044f7 --- /dev/null +++ b/.fides/celery.toml @@ -0,0 +1,2 @@ +event_queue_prefix = "fidesops_worker" +task_default_queue = "fidesops" diff --git a/.fides/dataset.yml b/.fides/db_dataset.yml similarity index 54% rename from .fides/dataset.yml rename to .fides/db_dataset.yml index 6c5123b235..76b1ac6a75 100644 --- a/.fides/dataset.yml +++ b/.fides/db_dataset.yml @@ -1,149 +1,112 @@ dataset: -- fides_key: public +- fides_key: fides_db organization_fides_key: default_organization - tags: null name: public - description: The dataset responsible for storing all of the data related to a fidesctl - instance. + description: The dataset for the fides application. meta: {} data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - fidesctl_meta: null - joint_controller: null retention: 1 year post employment - third_country_transfers: null collections: + - name: accessmanualwebhook + description: 'Fides Generated Description for Table: accessmanualwebhook' + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: connection_config_id + description: 'Fides Generated Description for Column: connection_config_id' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: created_at + description: 'Fides Generated Description for Column: created_at' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: fields + description: 'Fides Generated Description for Column: fields' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + description: 'Fides Generated Description for Column: id' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + description: 'Fides Generated Description for Column: updated_at' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - name: alembic_version - description: null - data_categories: null data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null fields: - name: version_num - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: auditlog - description: null - data_categories: null data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null fields: - name: created_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: action - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: message - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: privacy_request_id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: updated_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: user_id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: client - description: null - data_categories: null data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null fields: - name: created_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: hashed_secret - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: salt - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: scopes - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: updated_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: user_id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: cls_classification_detail description: 'Fides Generated Description for Table: cls_classification_detail' data_categories: null @@ -245,162 +208,93 @@ dataset: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - name: ctl_data_categories - description: null - data_categories: null data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null fields: - name: created_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: description - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: name - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: organization_fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: parent_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: tags - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: updated_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: is_default - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: ctl_data_qualifiers - description: null - data_categories: null data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null fields: - name: created_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: description - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: name - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: organization_fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: parent_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: tags - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: updated_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: is_default - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: ctl_data_subjects - description: null - data_categories: null data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null fields: - name: automated_decisions_or_profiling description: Boolean value representing if automated decisions or profiling @@ -408,253 +302,150 @@ dataset: data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: created_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: description - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: name - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: organization_fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: rights description: JSON structure containing a strategy and optional values for detailing data subject rights available data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: tags - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: updated_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: is_default - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: ctl_data_uses - description: null - data_categories: null data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null fields: - name: created_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: description - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: legal_basis - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: legitimate_interest description: Boolean value denoting whether or not the data use is marked as a legitimate interest data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: legitimate_interest_impact_assessment description: A url pointing to a legitimate interest impact assessment data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: name - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: organization_fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: parent_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: recipients - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: special_category - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: tags - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: updated_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: is_default - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: ctl_datasets - description: null - data_categories: null data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null fields: - name: collections - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: created_at description: The timestamp of when the row was created data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: data_categories - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: data_qualifier - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: description - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: fidesctl_meta - description: Metadata specifically for the fidesctl application data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: joint_controller description: Encrypted contact information for a joint controller (name, address, email, phone) @@ -662,263 +453,159 @@ dataset: - user.contact data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified retention: End of joint controller agreement. - fields: null - name: legal_basis description: The legal basis for processing personal data as defined by Article 6 of the GDPR data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: meta - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: name - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: organization_fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: recipients description: An array of recipients of the intended data use. data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: retention description: A string representing how long the dataset is retained for. Can also be found and applied as a property within Collections and Fields. data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: special_category description: The special category as defined by Article 9 of the GDPR data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: tags - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: third_country_transfers - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: updated_at description: The timestamp of when the row was last updated data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: ctl_evaluations - description: null - data_categories: null data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null fields: - name: created_at description: The timestamp of when the row was created data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: details - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: message - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: status - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: updated_at description: The timestamp of when the row was last updated data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: violations - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: fidesuser - description: null - data_categories: null data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null fields: - name: created_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: first_name - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: hashed_password - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: last_login_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: last_name - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: password_reset_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: salt - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: updated_at description: The timestamp of when the row was created data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: username - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: fidesuserpermissions - description: null - data_categories: null data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null fields: - name: created_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: scopes - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: updated_at - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: user_id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: ctl_organizations - description: null - data_categories: null data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null fields: - name: controller description: Encrypted contact information for the controller (name, address, @@ -927,14 +614,11 @@ dataset: - user.contact data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified retention: 1 Year post-employment - fields: null - name: created_at description: The timestamp of when the row was created data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: data_protection_officer description: Encrypted contact information for the Data Protection Officer (name, address, email, phone) @@ -942,56 +626,34 @@ dataset: - user.contact data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified retention: 1 Year post-employment - fields: null - name: description - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: fidesctl_meta - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: name - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: organization_fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: organization_parent_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: representative description: Encrypted contact information for the representative (name, address, email, phone) @@ -999,196 +661,121 @@ dataset: - user.contact data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified retention: 1 Year post-employment - fields: null - name: security_policy description: A link to the Ethyca security policy data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: tags - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: updated_at description: The timestamp of when the row was last updated data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: ctl_policies - description: null - data_categories: null data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null fields: - name: created_at description: The timestamp of when the row was created data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: description - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: name - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: organization_fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: rules - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: tags - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: updated_at description: The timestamp of when the row was last updated data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: ctl_registries - description: null - data_categories: null data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null fields: - name: created_at description: The timestamp of when the row was created data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: description - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: name - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: organization_fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: tags - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: updated_at description: The timestamp of when the row was last updated data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: ctl_systems - description: null - data_categories: null data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null fields: - name: administrating_department - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: created_at description: The timestamp of when the row was created data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: data_protection_impact_assessment description: Properties identifying if a DPIA is required, the status of it, and a link if applicable. data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: data_responsibility_title - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: description - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified @@ -1201,21 +788,28 @@ dataset: data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified retention: null fields: null - - name: fides_key + - name: egress description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified retention: null fields: null + - name: fides_key + data_categories: + - system.operations + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - name: fidesctl_meta - description: null + data_categories: + - system.operations + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified retention: null fields: null - - name: id + - name: ingress description: null data_categories: - system.operations @@ -1236,74 +830,599 @@ dataset: - user.contact data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified retention: End of joint controller agreement. - fields: null - name: meta - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: name - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: organization_fides_key - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: privacy_declarations - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: registry_id - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: system_dependencies - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: system_type - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: tags - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: third_country_transfers - description: null data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null - name: updated_at description: The timestamp of when the row was last updated data_categories: - system.operations data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - retention: null - fields: null + - name: emailconfig + description: 'Fides Generated Description for Table: emailconfig' + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: created_at + description: 'Fides Generated Description for Column: created_at' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: details + description: 'Fides Generated Description for Column: details' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + description: 'Fides Generated Description for Column: id' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: key + description: 'Fides Generated Description for Column: key' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: name + description: 'Fides Generated Description for Column: name' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: secrets + description: 'Fides Generated Description for Column: secrets' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: service_type + description: 'Fides Generated Description for Column: service_type' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + description: 'Fides Generated Description for Column: updated_at' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: authenticationrequest + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: connection_key + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: state + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: client + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: fides_key + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: hashed_secret + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: salt + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: scopes + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: user_id + data_categories: [user.unique_id] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: connectionconfig + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: access + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: connection_type + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: description + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: disabled + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: disabled_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: key + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: last_test_succeeded + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: last_test_timestamp + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: name + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: saas_config + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: secrets + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: consent + description: 'Fides Generated Description for Table: consent' + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: data_use + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: data_use_description + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: opt_in + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: provided_identity_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: consentrequest + description: 'Fides Generated Description for Table: consentrequest' + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: created_at + description: 'Fides Generated Description for Column: created_at' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + description: 'Fides Generated Description for Column: id' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: provided_identity_id + description: 'Fides Generated Description for Column: provided_identity_id' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + description: 'Fides Generated Description for Column: updated_at' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: datasetconfig + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: connection_config_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: dataset + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: fides_key + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: executionlog + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: action_type + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: collection_name + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: dataset_name + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: fields_affected + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: message + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: privacy_request_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: status + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + + - name: fidesuser + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: first_name + data_categories: [user.name] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: hashed_password + data_categories: [user.credentials.password] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [user.unique_id] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: last_login_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: last_name + data_categories: [user.name] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: password_reset_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: salt + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: username + data_categories: [user.credentials] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: fidesuserpermissions + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: scopes + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: user_id + data_categories: [user.unique_id] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: policy + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: client_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: execution_timeframe + description: 'Fides Generated Description for Column: execution_timeframe' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: drp_action + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: key + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: name + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: policypostwebhook + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: connection_config_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: direction + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: key + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: name + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: order + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: policy_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: policyprewebhook + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: connection_config_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: direction + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: key + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: name + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: order + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: policy_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: privacyrequest + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: cancel_reason + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: canceled_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: client_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: due_date + description: 'Fides Generated Description for Column: due_date' + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: external_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: finished_processing_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: identity_verified_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: origin + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: paused_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: policy_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: requested_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: reviewed_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: reviewed_by + data_categories: [user.name] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: started_processing_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: status + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: providedidentity + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: encrypted_value + data_categories: [user.contact, user.unique_id] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: field_name + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: hashed_value + data_categories: [user.contact, user.unique_id] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: privacy_request_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: rule + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: action_type + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: client_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: key + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: masking_strategy + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: name + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: policy_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: storage_destination_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: ruletarget + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: client_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: data_category + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: key + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: name + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: rule_id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: storageconfig + data_categories: [] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fields: + - name: created_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: details + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: format + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: id + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: key + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: name + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: secrets + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: type + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + - name: updated_at + data_categories: [system.operations] + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified diff --git a/.fides/fides.toml b/.fides/fides.toml new file mode 100644 index 0000000000..e12f1bb177 --- /dev/null +++ b/.fides/fides.toml @@ -0,0 +1,56 @@ +[database] +server = "fides-db" +user = "postgres" +password = "fides" +port = "5432" +db = "fides" +test_db = "fides_test" + +[credentials] +app_postgres = {connection_string="postgresql+psycopg2://postgres:fides@fides-db:5432/fides_test"} + +[logging] +level = "INFO" + +[cli] +server_host = "localhost" +server_port = 8080 + +[user] +analytics_opt_out = false + +[redis] +host = "redis" +password = "testpassword" +port = 6379 +charset = "utf8" +default_ttl_seconds = 604800 +db_index = 0 +ssl = false +ssl_cert_reqs = "required" + +[security] +app_encryption_key = "OLMkv91j8DHiDAULnK5Lxx3kSCov30b3" +cors_origins = [ "http://localhost", "http://localhost:8080", "http://localhost:3000", "http://localhost:3001",] +encoding = "UTF-8" +oauth_root_client_id = "fidesopsadmin" +oauth_root_client_secret = "fidesopsadminsecret" +drp_jwt_secret = "secret" +root_username = "root_user" +root_password = "Testpassword1!" + +[execution] +masking_strict = true +require_manual_request_approval = false +task_retry_backoff = 1 +subject_identity_verification_required = false +task_retry_count = 0 +task_retry_delay = 1 + +[admin_ui] +enabled = true + +[notifications] +send_request_completion_notification = true +send_request_receipt_notification = true +send_request_review_notification = true diff --git a/.fides/fidesctl.toml b/.fides/fidesctl.toml deleted file mode 100644 index d53452be48..0000000000 --- a/.fides/fidesctl.toml +++ /dev/null @@ -1,17 +0,0 @@ -[database] -server = "fidesctl-db" -user = "postgres" -password = "fidesctl" -port = "5432" -db = "fidesctl" -test_db = "fidesctl_test" - -[logging] -level = "INFO" - -[cli] -server_host = "localhost" -server_port = 8080 - -[user] -analytics_opt_out = false diff --git a/.fides/policy.yml b/.fides/policies.yml similarity index 53% rename from .fides/policy.yml rename to .fides/policies.yml index 545f099d4c..30da1592d7 100644 --- a/.fides/policy.yml +++ b/.fides/policies.yml @@ -1,28 +1,8 @@ policy: -- fides_key: fidesctl_policy - organization_fides_key: default_organization - tags: null - name: Fidesctl Policy - description: The main privacy policy for Fidesctl. - rules: - - name: reject_non_system_data - data_categories: - matches: OTHER - values: - - system.operations - data_uses: - matches: OTHER - values: - - provide - data_subjects: - matches: OTHER - values: - - anonymous_user - data_qualifier: aggregated + - fides_key: data_sharing_policy - organization_fides_key: default_organization - tags: null name: Data Sharing + organization_fides_key: default_organization description: The privacy policy that governs sharing of data with third parties. rules: - name: Disallow Third-Party Marketing diff --git a/.fides/redis_dataset.yml b/.fides/redis_dataset.yml new file mode 100644 index 0000000000..2a7f7beec1 --- /dev/null +++ b/.fides/redis_dataset.yml @@ -0,0 +1,126 @@ +dataset: + - fides_key: fides_cache + name: Fides Redis Cache + description: Fields stored in temporary storage to support Fides request execution + collections: + - name: hash_table + fields: + - name: EN_ACCESS_GRAPH__ + description: This graph is summarized and sent to Fideslog to create high level insight into how graphs change between retries to inform future features. + data_categories: + - system.operations + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fidesops_meta: + data_type: object # Stores an encrypted representation of the fidesops graph that executes the privacy requests. + fields: + - name: : # The current collection + data_categories: + - system.operations + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + fidesops_meta: + data_type: object + fields: + - name: : # An upstream collection + data_categories: [system.operations] + fidesops_meta: + data_type: string[] # List of edges between the upstream collection and the current collection + - name: EN_EMAIL_INFORMATION________ # Usage: For building emails associated with email-connector datasets at the end of the privacy request. This encrypted raw information is retrieved from each relevant email-based collection and used to build a single email per email connector, with instructions on how to mask data on the given dataset. + fidesops_meta: + data_type: object # Stores how to locate and mask records for a given "email" collection. + fields: + - name: step # Currently always "erasure". The email connector only sends emails for erasure requests. + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: collection # : + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: action_needed + fidesops_meta: + data_type: object[] + fields: + - name: locators + data_categories: [user] + fidesops_meta: + data_type: object # Field names mapped to values that should be used to locate the relevant records to mask + - name: get # Always None for this "action required" cache + - name: update + fidesops_meta: + data_type: object # Field names (nested fields are dot-separated) mapped to the masking value + - name: EN_FAILED_LOCATION__ # Usage: Used to resume a privacy request from a particular checkpoint. + fidesops_meta: + data_type: object + fields: + - name: step # The particular checkpoint where the privacy request failed. Only one checkpoint can be cached at a time. + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: collection # dataset_name:collection_name # Optional. If the privacy request failed inside the graph, the particular dataset/collection where it failed. + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: EN_MANUAL_INPUT____: # Usage: To store data uploaded by a human for a given manual collection which can be used to query downstream dependent results and later filtered and returned to the user. This is for the Manual Connector, which is integrated with the graph. + fidesops_meta: + data_type: object[] # A list of rows manually uploaded for a given collection. The fields will be entirely dependent on the collection in question. + - name: EN_MANUAL_MASK____: # Usage: To have an erasure for a Manual Connector (which is integrated with the graph) return the same information that an automated connector returns. This allows a user to confirm they've manually masked data on their end for a given collection. + data_categories: [system.operations] + fidesops_meta: + data_type: integer # A count of records manually erased for a given collection + - name: EN_PAUSED_LOCATION__ # Usage: Caches the location where a privacy request is paused and awaiting input by a manual connector. Manual data should be uploaded corresponding to this cached location. Manual connectors are integrated with the graph. + fidesops_meta: + data_type: object + fields: + - name: step # Either access or erasure + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: collection # dataset_name:collection_name. The given collection where the manual connector is awaiting input. + data_categories: [system.operations] + fidesops_meta: + data_type: string + - name: action_needed + fidesops_meta: + data_type: object[] + fields: + - name: locators + data_type: object # Field names mapped to values that should be used to manually locate the record(s) associated with a given subject + - name: get # Applicable if we're paused on the "access" step. A list of field names on the current collection that should be retrieved. + data_categories: [user] + data_type: string[] + - name: update # Applicable if we're paused on the "erasure" step + data_type: object # Field names mapped to the values that should be used to mask + - name: EN_PLACEHOLDER_RESULTS____access_request__: # Usage: Saves the access data that we should use to perform the erasure request. Access request data is a prerequisite to running an erasure. + fidesops_meta: + data_type: object[] # A list of encrypted rows. This separate representation of access results is stored to indicate which array elements are not applicable to the given data subject. + - name: EN___access_request__: # Usage: These are the results of the access request for a given collection. These rows are used to find data in dependent collections downstream and are later filtered by data category and returned to the user. + fidesops_meta: + data_type: object[] # A list of encrypted rows retrieved from the given collection in an access request. + - name: EN___erasure_request__: # Usage: For retrying a privacy request after pause or failure, lets us know that an erasure was already performed on this collection, so we don't attempt again. + data_categories: [system.operations] + fidesops_meta: + data_type: integer # An encrypted count of records masked on the given collection + - name: EN_WEBHOOK_MANUAL_INPUT____ # Usage: Stores fields manually uploaded for a *webhook* to be returned directly to the user at the end of the privacy request. Manual webhooks run before the graph, as opposed to manual connectors which collect manual data as *part* of the graph. + fidesops_meta: + data_type: object # A single record that was manually uploaded for the given manual webhook (all dynamic fields may be user-related) + - name: id--async-execution # Usage: May not be using yet, but tying a privacy request to its celery task could give us more insight into its current status in the future. + data_categories: [system.operations] + fidesops_meta: + data_type: string # Stores the privacy request's celery task id + - name: id--drp-" # Usage: For DRP troubleshooting. Individually caches portions of the drp request body. Can map to multiple scalar values. + - name: id--encryption-key # Usage: Used to encrypt access request results before uploading to the user + fidesops_meta: + data_categories: [system.operations] + data_type: string # Sets the fidesops encryption key. + - name: id--identity- # Usage: For caching the users' identity to be used in privacy request execution. For example, identity attribute might be "email" or "phone_number" + data_categories: [user] + fidesops_meta: + data_type: string + - name: id--masking-secret-- # Usage: To carry out erasure requests using certain masking strategies that need secrets + data_categories: [system.operations] + fidesops_meta: + data_type: string # An automatically generated secret that should be used in conjunction with the given masking strategy + - name: IDENTITY_VERIFICATION_CODE__ # Usage: To verify the user's identity before executing a privacy request. + data_categories: [system.operations] + fidesops_meta: + data_type: string # A stringified version of a six-digit identification number diff --git a/.fides/system.yml b/.fides/system.yml deleted file mode 100644 index 9fb4d6ee37..0000000000 --- a/.fides/system.yml +++ /dev/null @@ -1,29 +0,0 @@ -system: -- fides_key: fidesctl_system - organization_fides_key: default_organization - name: Fidesctl System - description: Software that functionally applies Fides. - registry_id: null - meta: null - fidesctl_meta: null - system_type: Service - data_responsibility_title: Controller - privacy_declarations: - - name: Store system data. - data_categories: - - system.operations - - user.contact - data_use: improve.system - data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified - data_subjects: - - anonymous_user - dataset_references: - - public - system_dependencies: null - joint_controller: null - third_country_transfers: null - administrating_department: Not defined - data_protection_impact_assessment: - is_required: false - progress: null - link: null diff --git a/.fides/systems.yml b/.fides/systems.yml new file mode 100644 index 0000000000..e5d36896f2 --- /dev/null +++ b/.fides/systems.yml @@ -0,0 +1,88 @@ +system: + # System Info + - fides_key: privacy_annotations + name: Fides Privacy Annotations + organization_fides_key: default_organization + description: Privacy annotations as code. + system_type: Service + # RoPA Info - these need to exist to pass an audit + data_responsibility_title: Controller + data_protection_impact_assessment: + is_required: false + progress: null + link: null + joint_controller: null + third_country_transfers: null + administrating_department: Not defined + # Privacy Declarations + privacy_declarations: + - name: Store fidesctl annotation data. + data_categories: + - system.operations + - user.contact + data_use: improve.system + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + data_subjects: + - anonymous_user + dataset_references: + - fides_db + + # System Info + - fides_key: privacy_request_fullfillment + name: Fides Privacy Request Fulfillment + organization_fides_key: default_organization + description: Privacy request fufillment. + system_type: Application + # RoPA Info - these need to exist to pass an audit + data_responsibility_title: Controller + data_protection_impact_assessment: + is_required: false + progress: null + link: null + joint_controller: null + third_country_transfers: null + administrating_department: Not defined + # Privacy Declarations + privacy_declarations: + - name: Manage privacy request Fufillment + data_categories: [] # comprehensive list of data categories in `fides_db` + data_use: provide.service + data_subjects: + - customer + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + dataset_references: + - fides_db + - fides_cache + + # System Info + - fides_key: admin_ui + name: Fides Administration UI + organization_fides_key: default_organization + description: Fides administration UI. + system_type: Application + # RoPA Info - these need to exist to pass an audit + data_responsibility_title: Controller + data_protection_impact_assessment: + is_required: false + progress: null + link: null + joint_controller: null + third_country_transfers: null + administrating_department: Not defined + # Privacy Declarations + privacy_declarations: + - name: Manage privacy request Fufillment + data_categories: [] # comprehensive list of data categories in `fides_db` + data_use: provide.service + data_subjects: + - employee + data_qualifier: aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified + dataset_references: + - fides_db + # Specific tables for reference + # - fides_db.client + # - fides_db.connectionconfig + # - fides_db.fidesuser + # - fides_db.fidesuserpermissions + # - fides_db.providedidentity + # - fides_db.privacyrequest diff --git a/.gitattributes b/.gitattributes index d2fc909941..254007f175 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -src/fidesctl/_version.py export-subst +src/fides/_version.py export-subst diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000000..adcf4706e0 --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,34 @@ +version: 2 +updates: + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + labels: + - dependencies + - python + - dependabot + - package-ecosystem: npm + directory: "/clients/ops/admin-ui" + schedule: + interval: weekly + labels: + - dependencies + - javascript + - dependabot + - package-ecosystem: npm + directory: "/clients/ops/privacy-center" + schedule: + interval: weekly + labels: + - dependencies + - javascript + - dependabot + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly + labels: + - dependencies + - github_actions + - dependabot diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 966804df3d..4766d48d49 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -12,8 +12,8 @@ Closes * [ ] All CI Pipelines Succeeded * Documentation Updated: - - [ ] documentation complete, or draft/outline provided (tag docs-team to complete/review on this branch) - - [ ] documentation issue created (tag docs-team to complete issue separately) + * [ ] documentation complete, or draft/outline provided (tag docs-team to complete/review on this branch) + * [ ] documentation issue created (tag docs-team to complete issue separately) * [ ] Issue Requirements are Met * [ ] Relevant Follow-Up Issues Created * [ ] Update `CHANGELOG.md` diff --git a/.github/workflows/backend_checks.yml b/.github/workflows/backend_checks.yml new file mode 100644 index 0000000000..0c795186e5 --- /dev/null +++ b/.github/workflows/backend_checks.yml @@ -0,0 +1,391 @@ +name: Backend Code Checks + +on: + pull_request: + paths-ignore: + - "**.md" + +env: + IMAGE: ethyca/fides:local + DEFAULT_PYTHON_VERSION: "3.10.6" + +jobs: + Build: + strategy: + matrix: + python_version: ["3.8.14", "3.9.14", "3.10.6"] + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v2 + + - name: Build container + uses: docker/build-push-action@v2 + with: + builder: ${{ steps.buildx.outputs.name }} + context: . + build-args: PYTHON_VERSION=${{ matrix.python_version }} + target: prod + outputs: type=docker,dest=/tmp/python-${{ matrix.python_version }}.tar + push: false + tags: ${{ env.IMAGE }} + + - name: Upload container + uses: actions/upload-artifact@v3 + with: + name: python-${{ matrix.python_version }} + path: /tmp/python-${{ matrix.python_version }}.tar + retention-days: 1 + +################### +## Static Checks ## +################### + isort: + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: ${{ env.DEFAULT_PYTHON_VERSION }} + + - name: Install Nox + run: pip install nox>=2022 + + - name: Run sorter + run: nox -s isort + + Black: + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v3 + + - name: set up python + uses: actions/setup-python@v3 + with: + python-version: ${{ env.DEFAULT_PYTHON_VERSION }} + + - name: Install Nox + run: pip install nox>=2022 + + - name: Run formatter + run: nox -s black + + Pylint: + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v3 + + - name: set up python + uses: actions/setup-python@v3 + with: + python-version: ${{ env.DEFAULT_PYTHON_VERSION }} + + - name: Install Nox + run: pip install nox>=2022 + + - name: Run linter + run: nox -s pylint + + Mypy: + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v3 + + - name: set up python + uses: actions/setup-python@v3 + with: + python-version: ${{ env.DEFAULT_PYTHON_VERSION }} + + - name: Install Nox + run: pip install nox>=2022 + + - name: Run typechecker + run: nox -s mypy + + Xenon: + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v3 + + - name: set up python + uses: actions/setup-python@v3 + with: + python-version: ${{ env.DEFAULT_PYTHON_VERSION }} + + - name: Install Nox + run: pip install nox>=2022 + + - name: Run cyclomatic complexity check + run: nox -s xenon + +######################## +## Application Checks ## +######################## + Docs: + needs: Build + runs-on: ubuntu-latest + steps: + - name: Download container + uses: actions/download-artifact@v3 + with: + name: python-${{ env.DEFAULT_PYTHON_VERSION }} + path: /tmp/ + + - name: Load image + run: docker load --input /tmp/python-${{ env.DEFAULT_PYTHON_VERSION }}.tar + + - name: Checkout + uses: actions/checkout@v3 + + - name: Install Nox + run: pip install nox>=2022 + + - name: Check that the docs can build + run: nox -s docs_check + + Fides-Checks: + needs: Build + runs-on: ubuntu-latest + steps: + - name: Download container + uses: actions/download-artifact@v3 + with: + name: python-${{ env.DEFAULT_PYTHON_VERSION }} + path: /tmp/ + + - name: Load image + run: docker load --input /tmp/python-${{ env.DEFAULT_PYTHON_VERSION }}.tar + + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: ${{ env.DEFAULT_PYTHON_VERSION }} + + - name: Install Nox + run: pip install nox>=2022 + + - name: Check fides installation + run: nox -s check_install + + - name: Run fides evaluation + run: nox -s check_fides_annotations -- docker + + - name: Scan fides db + run: nox -s fides_db_scan + +################ +## Safe Tests ## +################ + Pytest-Ctl-Not-External: + needs: Build + strategy: + matrix: + python_version: ["3.8.14", "3.9.14", "3.10.6"] + runs-on: ubuntu-latest + continue-on-error: true + steps: + - name: Download container + uses: actions/download-artifact@v3 + with: + name: python-${{ matrix.python_version }} + path: /tmp/ + + - name: Load image + run: docker load --input /tmp/python-${{ matrix.python_version }}.tar + + - name: Checkout + uses: actions/checkout@v3 + + - name: Install Nox + run: pip install nox>=2022 + + - name: Run non-external test suite + run: nox -s "pytest_ctl(not-external)" + + + Pytest-Unit-Ops: + needs: Build + strategy: + matrix: + python_version: ["3.8.14", "3.9.14", "3.10.6"] + runs-on: ubuntu-latest + continue-on-error: true + steps: + - name: Download container + uses: actions/download-artifact@v3 + with: + name: python-${{ matrix.python_version }} + path: /tmp/ + + - name: Load image + run: docker load --input /tmp/python-${{ matrix.python_version }}.tar + + - name: Checkout + uses: actions/checkout@v3 + + - name: Install Nox + run: pip install nox>=2022 + + - name: Run unit test suite + run: nox -s "pytest_ops(unit)" + + Pytest-Integration-Ops: + needs: Build + strategy: + matrix: + python_version: ["3.8.14", "3.9.14", "3.10.6"] + runs-on: ubuntu-latest + continue-on-error: true + steps: + - name: Download container + uses: actions/download-artifact@v3 + with: + name: python-${{ matrix.python_version }} + path: /tmp/ + + - name: Load image + run: docker load --input /tmp/python-${{ matrix.python_version }}.tar + + - name: Checkout + uses: actions/checkout@v3 + + - name: Install Nox + run: pip install nox>=2022 + + - name: Run integration test suite + run: nox -s "pytest_ops(integration)" + +################## +## Unsafe Tests ## +################## + Pytest-Ctl-External: + needs: Build + strategy: + max-parallel: 1 # This prevents collisions in shared external resources + matrix: + python_version: ["3.8.14", "3.9.14", "3.10.6"] + runs-on: ubuntu-latest + if: contains(github.event.pull_request.labels.*.name, 'run unsafe ci checks') + continue-on-error: true + steps: + - name: Download container + uses: actions/download-artifact@v3 + with: + name: python-${{ matrix.python_version }} + path: /tmp/ + + - name: Load image + run: docker load --input /tmp/python-${{ matrix.python_version }}.tar + + - name: Checkout + uses: actions/checkout@v3 + + - name: Install Nox + run: pip install nox>=2022 + + - name: Run external test suite + run: nox -s "pytest_ctl(external)" + env: + SNOWFLAKE_FIDESCTL_PASSWORD: ${{ secrets.SNOWFLAKE_FIDESCTL_PASSWORD }} + REDSHIFT_FIDESCTL_PASSWORD: ${{ secrets.REDSHIFT_FIDESCTL_PASSWORD }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_FIDESCTL_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_FIDESCTL_ACCESS_KEY }} + OKTA_CLIENT_TOKEN: ${{ secrets.OKTA_FIDESCTL_CLIENT_TOKEN }} + AWS_DEFAULT_REGION: us-east-1 + BIGQUERY_CONFIG: ${{ secrets.BIGQUERY_CONFIG }} + + External-Datastores: + needs: Build + strategy: + max-parallel: 1 # This prevents collisions in shared external resources + matrix: + python_version: ["3.8.14", "3.9.14", "3.10.6"] + runs-on: ubuntu-latest + if: contains(github.event.pull_request.labels.*.name, 'run unsafe ci checks') + continue-on-error: true + steps: + - name: Download container + uses: actions/download-artifact@v3 + with: + name: python-${{ matrix.python_version }} + path: /tmp/ + + - name: Load image + run: docker load --input /tmp/python-${{ matrix.python_version }}.tar + + - name: Checkout + uses: actions/checkout@v3 + + - name: Install Nox + run: pip install nox>=2022 + + - name: Integration Tests (External) + env: + REDSHIFT_TEST_URI: ${{ secrets.REDSHIFT_TEST_URI }} + REDSHIFT_TEST_DB_SCHEMA: fidesops_test + BIGQUERY_KEYFILE_CREDS: ${{ secrets.BIGQUERY_KEYFILE_CREDS }} + BIGQUERY_DATASET: fidesopstest + SNOWFLAKE_TEST_URI: ${{ secrets.SNOWFLAKE_TEST_URI }} + run: nox -s "pytest_ops(external-datastores)" + + External-SaaS-Connectors: + needs: Build + runs-on: ubuntu-latest + continue-on-error: true + if: contains(github.event.pull_request.labels.*.name, 'run unsafe ci checks') + permissions: + contents: read + id-token: write + strategy: + max-parallel: 1 # This prevents collisions in shared external resources + matrix: + python_version: ["3.8.14", "3.9.14", "3.10.6"] + steps: + - name: Download container + uses: actions/download-artifact@v3 + with: + name: python-${{ matrix.python_version }} + path: /tmp/ + + - name: Load image + run: docker load --input /tmp/python-${{ matrix.python_version }}.tar + + - name: Install Nox + run: pip install nox>=2022 + + - name: Checkout + uses: actions/checkout@v3 + + - name: Get Vault Token + uses: hashicorp/vault-action@v2.4.2 + with: + url: ${{ secrets.VAULT_ADDR }} + namespace: ${{ secrets.VAULT_NAMESPACE }} + method: jwt + role: ${{ secrets.VAULT_ROLE }} + exportToken: True + + - name: SaaS Connector Tests + env: + VAULT_ADDR: ${{ secrets.VAULT_ADDR }} + VAULT_NAMESPACE: ${{ secrets.VAULT_NAMESPACE }} + run: nox -s "pytest_ops(saas)" diff --git a/.github/workflows/code_checks.yml b/.github/workflows/code_checks.yml deleted file mode 100644 index 9bf7d2cc7d..0000000000 --- a/.github/workflows/code_checks.yml +++ /dev/null @@ -1,277 +0,0 @@ -name: Code Checks - -on: - pull_request: - paths-ignore: - - "**.md" - -env: - CONTAINER: fidesctl-local - IMAGE: ethyca/fidesctl:local - -jobs: - Build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v2 - - - name: Build fidesctl container - uses: docker/build-push-action@v2 - with: - builder: ${{ steps.buildx.outputs.name }} - context: . - target: prod - outputs: type=docker,dest=/tmp/${{ env.CONTAINER }}.tar - push: false - tags: ${{ env.IMAGE }} - - - name: Upload fidesctl container - uses: actions/upload-artifact@v3 - with: - name: ${{ env.CONTAINER }} - path: /tmp/${{ env.CONTAINER }}.tar - retention-days: 1 - - Fidesctl: - needs: Build - runs-on: ubuntu-latest - steps: - - name: Download fidesctl container - uses: actions/download-artifact@v3 - with: - name: ${{ env.CONTAINER }} - path: /tmp/ - - - name: Load fidesctl image - run: docker load --input /tmp/${{ env.CONTAINER }}.tar - - - name: Checkout - uses: actions/checkout@v3 - - - name: Set up Python 3.9 - uses: actions/setup-python@v3 - with: - python-version: "3.9" - - - name: Install Nox - run: pip install nox>=2022 - - - name: Check fidesctl installation - run: nox -s check_install -- docker - - - name: Run fidesctl evaluation - run: nox -s fidesctl -- docker - - - name: Scan fidesctl db - run: nox -s fidesctl_db_scan -- docker - - isort: - needs: Build - runs-on: ubuntu-latest - steps: - - name: Download fidesctl container - uses: actions/download-artifact@v3 - with: - name: ${{ env.CONTAINER }} - path: /tmp/ - - - name: Load fidesctl image - run: docker load --input /tmp/${{ env.CONTAINER }}.tar - - - name: Checkout - uses: actions/checkout@v3 - - - name: Install Nox - run: pip install nox>=2022 - - - name: Run sorter - run: nox -s isort -- docker - - Black: - needs: Build - runs-on: ubuntu-latest - steps: - - name: Download fidesctl container - uses: actions/download-artifact@v3 - with: - name: ${{ env.CONTAINER }} - path: /tmp/ - - - name: Load fidesctl image - run: docker load --input /tmp/${{ env.CONTAINER }}.tar - - - name: Checkout - uses: actions/checkout@v3 - - - name: Install Nox - run: pip install nox>=2022 - - - name: Run formatter - run: nox -s black -- docker - - Docs: - needs: Build - runs-on: ubuntu-latest - steps: - - name: Download fidesctl container - uses: actions/download-artifact@v3 - with: - name: ${{ env.CONTAINER }} - path: /tmp/ - - - name: Load fidesctl image - run: docker load --input /tmp/${{ env.CONTAINER }}.tar - - - name: Checkout - uses: actions/checkout@v3 - - - name: Install Nox - run: pip install nox>=2022 - - - name: Check that the docs can build - run: nox -s docs_check - - Pylint: - needs: Build - runs-on: ubuntu-latest - steps: - - name: Download fidesctl container - uses: actions/download-artifact@v3 - with: - name: ${{ env.CONTAINER }} - path: /tmp/ - - - name: Load fidesctl image - run: docker load --input /tmp/${{ env.CONTAINER }}.tar - - - name: Checkout - uses: actions/checkout@v3 - - - name: Install Nox - run: pip install nox>=2022 - - - name: Run linter - run: nox -s pylint -- docker - - Mypy: - needs: Build - runs-on: ubuntu-latest - steps: - - name: Download fidesctl container - uses: actions/download-artifact@v3 - with: - name: ${{ env.CONTAINER }} - path: /tmp/ - - - name: Load fidesctl image - run: docker load --input /tmp/${{ env.CONTAINER }}.tar - - - name: Checkout - uses: actions/checkout@v3 - - - name: Install Nox - run: pip install nox>=2022 - - - name: Run typechecker - run: nox -s mypy -- docker - - Xenon: - needs: Build - runs-on: ubuntu-latest - steps: - - name: Download fidesctl container - uses: actions/download-artifact@v3 - with: - name: ${{ env.CONTAINER }} - path: /tmp/ - - - name: Load fidesctl image - run: docker load --input /tmp/${{ env.CONTAINER }}.tar - - - name: Checkout - uses: actions/checkout@v3 - - - name: Install Nox - run: pip install nox>=2022 - - - name: Run cyclomatic complexity check - run: nox -s xenon -- docker - - Pytest-Unit: - needs: Build - runs-on: ubuntu-latest - steps: - - name: Download fidesctl container - uses: actions/download-artifact@v3 - with: - name: ${{ env.CONTAINER }} - path: /tmp/ - - - name: Load fidesctl image - run: docker load --input /tmp/${{ env.CONTAINER }}.tar - - - name: Checkout - uses: actions/checkout@v3 - - - name: Install Nox - run: pip install nox>=2022 - - - name: Run unit test suite - run: nox -s "pytest(unit)" - - Pytest-Integration: - needs: Build - runs-on: ubuntu-latest - steps: - - name: Download fidesctl container - uses: actions/download-artifact@v3 - with: - name: ${{ env.CONTAINER }} - path: /tmp/ - - - name: Load fidesctl image - run: docker load --input /tmp/${{ env.CONTAINER }}.tar - - - name: Checkout - uses: actions/checkout@v3 - - - name: Install Nox - run: pip install nox>=2022 - - - name: Run integration test suite - run: nox -s "pytest(integration)" - - Pytest-External: - needs: Build - runs-on: ubuntu-latest - steps: - - name: Download fidesctl container - uses: actions/download-artifact@v3 - with: - name: ${{ env.CONTAINER }} - path: /tmp/ - - - name: Load fidesctl image - run: docker load --input /tmp/${{ env.CONTAINER }}.tar - - - name: Checkout - uses: actions/checkout@v3 - - - name: Install Nox - run: pip install nox>=2022 - - - name: Run external test suite - run: nox -s pytest_external - env: - SNOWFLAKE_FIDESCTL_PASSWORD: ${{ secrets.SNOWFLAKE_FIDESCTL_PASSWORD }} - REDSHIFT_FIDESCTL_PASSWORD: ${{ secrets.REDSHIFT_FIDESCTL_PASSWORD }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_FIDESCTL_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_FIDESCTL_ACCESS_KEY }} - OKTA_CLIENT_TOKEN: ${{ secrets.OKTA_FIDESCTL_CLIENT_TOKEN }} - AWS_DEFAULT_REGION: us-east-1 - BIGQUERY_CONFIG: ${{ secrets.BIGQUERY_CONFIG }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000000..ec6cd000d9 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,70 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ main ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ main ] + schedule: + - cron: '00 6 * * 1' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'javascript', 'python' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://git.io/codeql-language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/frontend_pr_checks.yml b/.github/workflows/frontend_checks.yml similarity index 56% rename from .github/workflows/frontend_pr_checks.yml rename to .github/workflows/frontend_checks.yml index e7ce3a7cec..d976f80746 100644 --- a/.github/workflows/frontend_pr_checks.yml +++ b/.github/workflows/frontend_checks.yml @@ -1,4 +1,4 @@ -name: Frontend PR Checks +name: Frontend Code Checks on: pull_request: @@ -14,16 +14,16 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [16.x] + node-version: [ 16.x ] defaults: run: - working-directory: clients/ctl/admin-ui + working-directory: clients/admin-ui steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} @@ -33,11 +33,14 @@ jobs: - name: Lint run: npm run lint + - name: Format + run: npm run format:ci + - name: Jest test run: npm run test:ci - name: Build - run: npm run export + run: npm run build Admin-UI-Cypress: runs-on: ubuntu-latest @@ -55,21 +58,46 @@ jobs: - name: Install dependencies run: | - cd clients/ctl/admin-ui + cd clients/admin-ui npm install - name: Cypress E2E tests uses: cypress-io/github-action@v4 with: - working-directory: clients/ctl/admin-ui + working-directory: clients/admin-ui install: false start: npm run cy:start wait-on: "http://localhost:3000" wait-on-timeout: 120 - - name: Cypress component tests - uses: cypress-io/github-action@v4 + Privacy-Center-Unit: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [16.x] + defaults: + run: + working-directory: clients/ops/privacy-center + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 with: - working-directory: clients/ctl/admin-ui - install: false - component: true + node-version: ${{ matrix.node-version }} + + - name: Install dependencies + run: npm install + + - name: Lint + run: npm run lint + + - name: Format + run: npm run format:ci + + - name: Jest test + run: npm run test:ci + + - name: Build + run: npm run build diff --git a/.github/workflows/docker.yaml b/.github/workflows/publish_docker.yaml similarity index 98% rename from .github/workflows/docker.yaml rename to .github/workflows/publish_docker.yaml index a76050501f..4eba7aaccf 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/publish_docker.yaml @@ -12,7 +12,7 @@ env: DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} jobs: - push-fidesctl: + push-fides: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/publish_docs.yaml b/.github/workflows/publish_docs.yaml index 59f3ed7ae4..f62a2a29e1 100644 --- a/.github/workflows/publish_docs.yaml +++ b/.github/workflows/publish_docs.yaml @@ -30,7 +30,7 @@ jobs: - name: Install Docs Requirements run: pip install -r docs/fides/requirements.txt - - name: Install fidesctl + - name: Install fides run: pip install -e ./[all] - name: Checkout the gh-pages branches diff --git a/.github/workflows/publish_package.yaml b/.github/workflows/publish_package.yaml index ec0a261d9a..9738537402 100644 --- a/.github/workflows/publish_package.yaml +++ b/.github/workflows/publish_package.yaml @@ -1,4 +1,4 @@ -name: Publish fidesctl +name: Publish Fides on: push: @@ -27,12 +27,12 @@ jobs: - name: Install node modules run: | - cd clients/ctl/admin-ui + cd clients/admin-ui npm install - name: Build and export frontend files run: | - cd clients/ctl/admin-ui + cd clients/admin-ui npm run prod-export - name: Install Twine and wheel diff --git a/.github/workflows/publish_privacy_center_to_dockerhub.yaml b/.github/workflows/publish_privacy_center_to_dockerhub.yaml new file mode 100644 index 0000000000..2f05912dfb --- /dev/null +++ b/.github/workflows/publish_privacy_center_to_dockerhub.yaml @@ -0,0 +1,36 @@ +name: Docker Build & Push Privacy Center + +on: + push: + tags: + - "*" + +env: + DOCKER_USER: ethycaci + DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} + +jobs: + push-fides-privacy-center-image: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + username: ${{ env.DOCKER_USER }} + password: ${{ env.DOCKER_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v4 + with: + images: ethyca/fides-privacy-center + + - name: Build and publish + uses: docker/build-push-action@v3 + with: + context: ./clients/ops/privacy-center + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.metadata.outputs.labels }} diff --git a/.github/workflows/release_event.yml b/.github/workflows/release_event.yml index 58dd16f443..e3e9031eff 100644 --- a/.github/workflows/release_event.yml +++ b/.github/workflows/release_event.yml @@ -8,10 +8,11 @@ jobs: Notify-of-New-Release: runs-on: ubuntu-latest steps: + - name: Repository Dispatch uses: peter-evans/repository-dispatch@v2 with: token: ${{ secrets.DISPATCH_ACCESS_TOKEN }} - repository: ethyca/fidesctl-plus - event-type: new-fidesctl-release + repository: ethyca/fidesplus + event-type: new-fides-release client-payload: '{"tag": "${{ github.event.release.tag_name }}", "url": "${{ github.event.release.html_url }}"}' diff --git a/.gitignore b/.gitignore index 157fe84d09..82f6b6c40e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +# Source for the following rules: https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore + # frontend ui-build/ @@ -7,6 +9,7 @@ ui-build/ *.DS_Store *.swp *.out +*.tmp # rails specific *.sqlite3 @@ -20,7 +23,8 @@ tmp/* # docs docs/fides/site/ docs/fides/docs/api/openapi.json -docs/fides/docs/schemas/config_schema.json +docs/fidesops/docs/api/openapi.json +docs/fidesops/site # python specific *.pyc @@ -95,7 +99,6 @@ project/metals.sbt # Windows Thumbs.db -# Source for the following rules: https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -112,7 +115,6 @@ develop-eggs/ dist/ downloads/ eggs/ -.eggs/ lib/ lib64/ parts/ @@ -121,10 +123,13 @@ var/ wheels/ *egg-info/ !*egg-info/entry_points.txt # Required so that this works when mounted via docker-compose -.installed.cfg *.egg MANIFEST conda-out/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg # PyInstaller # Usually these files are written by a python script from a template @@ -157,6 +162,8 @@ coverage.xml *.log local_settings.py db.sqlite3 +db.sqlite3-journal +test.db # Flask stuff: instance/ @@ -184,12 +191,23 @@ ipython_config.py # celery beat schedule file celerybeat-schedule +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + # SageMath parsed files *.sage.py # Environments .env .venv +.env.local env/ venv/ ENV/ @@ -210,3 +228,30 @@ venv.bak/ .mypy_cache/ .dmypy.json dmypy.json + +# Pyre type checker +.pyre/ + +.idea + +# VSCode +.vscode/* + +# Congigure and save debugging details in VS Code launch.json file +!.vscode/launch.json + +*.code-workspace +.mypy_cache +docker-stack.yml +.DS_Store + +envfiles/ + +# Access request package local upload destination, generated at runtime +fides_uploads + +# Prevent SaaS configs from being committed +saas_config.toml + +# Script secrets +scripts/secrets.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b7643ad5af..192a224f4e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,34 +6,34 @@ repos: - id: docker name: docker entry: make build-local - files: "^fidesctl/" + files: "^fides/" types_or: [file, python] language: system - id: black name: black entry: make black - files: "^fidesctl/" + files: "^fides/" types_or: [file, python] language: system - id: mypy name: mypy entry: make mypy - files: "^fidesctl/" + files: "^fides/" types_or: [file, python] language: system - id: xenon name: xenon entry: make xenon - files: "^fidesctl/" + files: "^fides/" types_or: [file, python] language: system - id: pylint name: pylint entry: make pylint - files: "^fidesctl/" + files: "^fides/" types_or: [file, python] language: system diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..4d9109b9d8 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Chrome", + "request": "launch", + "type": "chrome", + "url": "http://localhost:3000", + "webRoot": "${workspaceFolder}/clients/ops/admin-ui" + }, + { + "name": "Attach to Chrome", + "port": 9222, + "request": "attach", + "type": "chrome", + "urlFilter": "http://localhost:3000/*", // use urlFilter instead of url! + "webRoot": "${workspaceFolder}/clients/ops/admin-ui" + } + ] +} + + + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 48263e4cfd..8ed8b38f4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,7 +61,11 @@ The types of changes are: * Changed behavior of `load_default_taxonomy` to append instead of upsert [#1040](https://github.com/ethyca/fides/pull/1040) * Changed behavior of adding privacy declarations to decouple the actions of the "add" and "next" buttons [#1086](https://github.com/ethyca/fides/pull/1086) * Moved system related UI components from the `config-wizard` directory to the `system` directory [#1097](https://github.com/ethyca/fides/pull/1097) -* Dataset fields table shows categories in the last column. [#1088](https://github.com/ethyca/fides/pull/1088) +* Updated "type" on SaaS config to be a simple string type, not an enum [#1197](https://github.com/ethyca/fides/pull/1197) + +### Developer Experience + +* Optional dependencies may have their version defined only once, in `optional-requirements.txt` [#1171](https://github.com/ethyca/fides/pull/1171) ### Docs @@ -128,12 +132,30 @@ The types of changes are: * Fixed an issue where `fides push --diff` would return a false positive diff [#1026](https://github.com/ethyca/fides/pull/1026) * Pinned pydantic version to < 1.10.0 to fix an error in finding referenced fides keys [#1045](https://github.com/ethyca/fides/pull/1045) +### Fixed + +* Fixed failing mypy tests [#1030](https://github.com/ethyca/fides/pull/1030) +* Fixed an issue where `fides push --diff` would return a false positive diff [#1026](https://github.com/ethyca/fides/pull/1026) + +### Docs + +* Minor formatting updates to [Policy Webhooks](https://ethyca.github.io/fidesops/guides/policy_webhooks/) documentation [#1114](https://github.com/ethyca/fidesops/pull/1114) + +### Removed + +* Removed create superuser [#1116](https://github.com/ethyca/fidesops/pull/1116) + ## [1.8.2](https://github.com/ethyca/fides/compare/1.8.1...1.8.2) - 2022-08-18 ### Added -* Added the ability to edit taxonomy fields via the UI [#977](https://github.com/ethyca/fides/pull/977) +* Added the ability to edit taxonomy fields via the UI [#977](https://github.com/ethyca/fides/pull/977) [#1028](https://github.com/ethyca/fides/pull/1028) * New column `is_default` added to DataCategory, DataUse, DataSubject, and DataQualifier tables [#976](https://github.com/ethyca/fides/pull/976) +* Added the ability to add taxonomy fields via the UI [#1019](https://github.com/ethyca/fides/pull/1019) +* Added the ability to delete taxonomy fields via the UI [#1006](https://github.com/ethyca/fides/pull/1006) + * Only non-default taxonomy entities can be deleted [#1023](https://github.com/ethyca/fides/pull/1023) +* Prevent deleting taxonomy `is_default` fields and from adding `is_default=True` fields via the API [#990](https://github.com/ethyca/fides/pull/990). +* Added a "Custom" tag to distinguish user defined taxonomy fields from default taxonomy fields in the UI [#1027](https://github.com/ethyca/fides/pull/1027) ### Changed @@ -339,9 +361,64 @@ The types of changes are: ### Added -* CHANGELOG.md file -* On API server startup, in-use config values are logged at the DEBUG level -* Send a usage analytics event upon execution of the `fidesctl init` command +* ESLint configuration changes [#514](https://github.com/ethyca/fidesops/pull/514) +* User creation, update and permissions in the Admin UI [#511](https://github.com/ethyca/fidesops/pull/511) +* Yaml support for dataset upload [#284](https://github.com/ethyca/fidesops/pull/284) + +### Breaking Changes + +* Update masking API to take multiple input values [#443](https://github.com/ethyca/fidesops/pull/443) + +### Docs + +* DRP feature documentation [#520](https://github.com/ethyca/fidesops/pull/520) + +## [1.4.2](https://github.com/ethyca/fidesops/compare/1.4.1...1.4.2) - 2022-05-12 + +### Added + +* GET routes for users [#405](https://github.com/ethyca/fidesops/pull/405) +* Username based search on GET route [#444](https://github.com/ethyca/fidesops/pull/444) +* FIDESOPS\_\_DEV_MODE for Easier SaaS Request Debugging [#363](https://github.com/ethyca/fidesops/pull/363) +* Track user privileges across sessions [#425](https://github.com/ethyca/fidesops/pull/425) +* Add first_name and last_name fields. Also add them along with created_at to FidesUser response [#465](https://github.com/ethyca/fidesops/pull/465) +* Denial reasons for DSR and user `AuditLog` [#463](https://github.com/ethyca/fidesops/pull/463) +* DRP action to Policy [#453](https://github.com/ethyca/fidesops/pull/453) +* `CHANGELOG.md` file[#484](https://github.com/ethyca/fidesops/pull/484) +* DRP status endpoint [#485](https://github.com/ethyca/fidesops/pull/485) +* DRP exerise endpoint [#496](https://github.com/ethyca/fidesops/pull/496) +* Frontend for privacy request denial reaons [#480](https://github.com/ethyca/fidesops/pull/480) +* Publish Fidesops to Pypi [#491](https://github.com/ethyca/fidesops/pull/491) +* DRP data rights endpoint [#526](https://github.com/ethyca/fidesops/pull/526) + +### Changed + +* Converted HTTP Status Codes to Starlette constant values [#438](https://github.com/ethyca/fidesops/pull/438) +* SaasConnector.send behavior on ignore_errors now returns raw response [#462](https://github.com/ethyca/fidesops/pull/462) +* Seed user permissions in `create_superuser.py` script [#468](https://github.com/ethyca/fidesops/pull/468) +* User API Endpoints (update fields and reset user passwords) [#471](https://github.com/ethyca/fidesops/pull/471) +* Format tests with `black` [#466](https://github.com/ethyca/fidesops/pull/466) +* Extract privacy request endpoint logic into separate service for DRP [#470](https://github.com/ethyca/fidesops/pull/470) +* Fixing inconsistent SaaS connector integration tests [#473](https://github.com/ethyca/fidesops/pull/473) +* Add user data to login response [#501](https://github.com/ethyca/fidesops/pull/501) + +### Breaking Changes + +* Update masking API to take multiple input values [#443](https://github.com/ethyca/fidesops/pull/443) + +### Docs + +* Added issue template for documentation updates [#442](https://github.com/ethyca/fidesops/pull/442) +* Clarify masking updates [#464](https://github.com/ethyca/fidesops/pull/464) +* Added dark mode [#476](https://github.com/ethyca/fidesops/pull/476) + +### Fixed + +* Removed miradb test warning [#436](https://github.com/ethyca/fidesops/pull/436) +* Added missing import [#448](https://github.com/ethyca/fidesops/pull/448) +* Removed pypi badge pointing to wrong package [#452](https://github.com/ethyca/fidesops/pull/452) +* Audit imports and references [#479](https://github.com/ethyca/fidesops/pull/479) +* Switch to using update method on PUT permission endpoint [#500](https://github.com/ethyca/fidesops/pull/500) ### Developer Experience diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 58bbf4e839..10675eac5c 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,5 +1,5 @@ -## Fides Code of Conduct +# Fides Code of Conduct -The Fides project, which includes Fideslang, Fidesops, and Fidesctl, adheres to the following [Code of Conduct](https://ethyca.github.io/fides/community/code_of_conduct/). +The Fides project, which includes fidescls and fideslang, adheres to the following [Code of Conduct](https://ethyca.github.io/fides/community/code_of_conduct/). The Fides core team welcomes any contributions and suggestions to help make the community a better place 🤝 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index baf64add5f..8b0652564a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,5 @@ -## Fides Contribution Guidelines +# Fides Contribution Guidelines -The Fides project, which includes Fideslang, Fidesops, and Fidesctl, adheres to the following [Contribution Guidelines](https://ethyca.github.io/fides/development/overview/). +The Fides project, which includes fidescls and fideslang, adheres to the following [Contribution Guidelines](https://ethyca.github.io/fides/development/overview/). The Fides core team welcomes any contributions and suggestions to help make the community a better place 🤝 diff --git a/Dockerfile b/Dockerfile index a0dedbe794..9502f9a29b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,55 +1,40 @@ -FROM --platform=linux/amd64 python:3.9-slim-bullseye as base - -# Update pip in the base image since we'll use it everywhere -RUN pip install -U pip - -#################### -## Build frontend ## -#################### +# Pin to 3.10.6 to avoid a mypy error in 3.10.7 +# If you update this, also update `DEFAULT_PYTHON_VERSION` +# in the GitHub workflow files +ARG PYTHON_VERSION=3.10.6 + +############## +## Frontend ## +############## FROM node:16 as frontend -WORKDIR /fides/clients/ctl/admin-ui - -# install node modules -COPY clients/ctl/admin-ui/ . +# Build the admin-io frontend +WORKDIR /fides/clients/admin-ui +COPY clients/admin-ui/ . RUN npm install - -# Build the frontend static files RUN npm run export -####################### -## Tool Installation ## -####################### +############# +## Backend ## +############# +FROM --platform=linux/amd64 python:${PYTHON_VERSION}-slim-bullseye as backend -FROM base as builder - -RUN : \ - && apt-get update \ - && apt-get install \ - -y --no-install-recommends \ - curl \ +# Install auxiliary software +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ git \ + make \ vim \ + curl \ g++ \ gnupg \ gcc \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -########################### -## Database Dependencies ## -########################### - -# Postgres -RUN : \ - && apt-get update \ - && apt-get install \ - -y --no-install-recommends \ - libpq-dev \ + python3-wheel \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # SQL Server (MS SQL) +# https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15 RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - RUN curl https://packages.microsoft.com/config/debian/11/prod.list | tee /etc/apt/sources.list.d/msprod.list ENV ACCEPT_EULA=y DEBIAN_FRONTEND=noninteractive @@ -67,53 +52,49 @@ RUN : \ ## Python Dependencies ## ######################### -COPY dev-requirements.txt dev-requirements.txt -RUN pip install -r dev-requirements.txt +COPY optional-requirements.txt . +RUN pip install -U pip --no-cache-dir install -r optional-requirements.txt -COPY requirements.txt requirements.txt -RUN pip install -r requirements.txt +COPY dev-requirements.txt . +RUN pip install -U pip --no-cache-dir install -r dev-requirements.txt -COPY optional-requirements.txt optional-requirements.txt -RUN pip install -r optional-requirements.txt +COPY requirements.txt . +RUN pip install -U pip --no-cache-dir install -r requirements.txt ############################### ## General Application Setup ## ############################### - COPY . /fides WORKDIR /fides +# Immediately flush to stdout, globally +ENV PYTHONUNBUFFERED=TRUE + # Reset the busted git cache RUN git rm --cached -r . RUN git reset --hard -# Immediately flush to stdout, globally -ENV PYTHONUNBUFFERED=TRUE - # Enable detection of running within Docker -ENV RUNNING_IN_DOCKER=TRUE +ENV RUNNING_IN_DOCKER=true EXPOSE 8080 -CMD ["fidesctl", "webserver"] - -################################### -## Application Development Setup ## -################################### +CMD [ "fides", "webserver" ] -FROM builder as dev +############################# +## Development Application ## +############################# +FROM backend as dev -# Install fidesctl as a symlink -RUN pip install --no-deps -e ".[all,mssql]" +RUN pip install -e . -################################## -## Production Application Setup ## -################################## - -FROM builder as prod - -# Copy frontend build over in order to be available in wheel package -COPY --from=frontend /fides/clients/ctl/admin-ui/out/ /fides/src/fidesctl/ui-build/static/admin/ +############################# +## Production Application ## +############################# +FROM backend as prod # Install without a symlink -RUN python setup.py bdist_wheel -RUN pip install --no-deps dist/fidesctl-*.whl +RUN python setup.py sdist +RUN pip install dist/ethyca-fides-*.tar.gz + +# Copy frontend build over +COPY --from=frontend /fides/clients/admin-ui/out/ /fides/src/fides/ui-build/static/admin diff --git a/MANIFEST.in b/MANIFEST.in index ded2c31711..1f62a87c7d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,16 @@ include LICENSE +include README.md include requirements.txt include dev-requirements.txt +include optional-requirements.txt include versioneer.py -include src/fidesctl/api/ctl/alembic.ini -include src/fidesctl/templates/fides_datamap_template.xlsx -recursive-include src/fidesctl/ui-build * \ No newline at end of file +include src/fides/api/ctl/alembic.ini +include src/fides/_version.py +include src/fides/py.typed +include src/fides/templates/fides_datamap_template.xlsx + +recursive-include src/fides/ui-build * + +graft src/fides/api/ops/email_templates/templates + +global-exclude *.pyc diff --git a/README.md b/README.md index 41e286abe0..0e8a224831 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Meet Fidesctl: Privacy Policies as Code +# Meet Fides: Privacy Policies as Code [![Latest Release Version][release-image]][release-url] [![Docker][docker-workflow-image]][docker-actions-url] @@ -47,7 +47,7 @@ This guide will walk through generating a mock RoPA using predefined resources i Once you see the `fides#` prompt (takes ~3 minutes the first time), you can run the next command: ``` - fidesctl init + fides init ``` This builds the required images, spins up the database, and runs the initialization scripts. @@ -55,19 +55,19 @@ This guide will walk through generating a mock RoPA using predefined resources i 3. Use the `export datamap` command to generate a [data map](/docs/fides/docs/guides/generating_datamap.md) of the provided [demo resources](demo_resources/): ```sh - fidesctl push demo_resources/ - fidesctl export datamap --output-dir demo_resources/ + fides push demo_resources/ + fides export datamap --output-dir demo_resources/ ``` This will `push` the provided demo resources, and `export` an `.xlsx` file of their contents to the `demo_resources/` directory. 4. View the newly-generated data map generated from the provided resources. - #### **Controller** +#### **Controller** The header block at the top of the data map is composed of properties found in the [Organization resource](/demo_resources/demo_organization.yml). In a production deployment, this would be composed of publicly available information for your company or organization. - #### **Article 30 Record of Processing Activities** +#### **Article 30 Record of Processing Activities** The remainder of the information on the data map is generated from the provided [configuration resources](https://ethyca.github.io/fides/language/resources/system). In a production environment, these could be [automatically generated](https://ethyca.github.io/fides/guides/generate_resources/) from your databases and system resources. @@ -152,8 +152,8 @@ Read about the [Fides community](https://ethyca.github.io/fides/community/hints_ ## :balance_scale: License -The Fides ecosystem of tools ([Fidesops](https://github.com/ethyca/fidesops) and [Fidesctl](https://github.com/ethyca/fides)) are licensed under the [Apache Software License Version 2.0](https://www.apache.org/licenses/LICENSE-2.0). -Fides tools are built on [Fideslang](https://github.com/ethyca/privacy-taxonomy), the Fides language specification, which is licensed under [CC by 4](https://github.com/ethyca/privacy-taxonomy/blob/main/LICENSE). +The Fides ecosystem of tools ([Fides](https://github.com/ethyca/fides) and [fidescls](https://github.com/ethyca/fidescls)) are licensed under the [Apache Software License Version 2.0](https://www.apache.org/licenses/LICENSE-2.0). +Fides tools are built on [fideslang](https://github.com/ethyca/privacy-taxonomy), the Fides language specification, which is licensed under [CC by 4](https://github.com/ethyca/privacy-taxonomy/blob/main/LICENSE). Fides is created and sponsored by Ethyca: a developer tools company building the trust infrastructure of the internet. If you have questions or need assistance getting started, let us know at fides@ethyca.com! diff --git a/clients/ctl/admin-ui/.babelrc b/clients/admin-ui/.babelrc similarity index 100% rename from clients/ctl/admin-ui/.babelrc rename to clients/admin-ui/.babelrc diff --git a/clients/ctl/admin-ui/.env.development b/clients/admin-ui/.env.development similarity index 65% rename from clients/ctl/admin-ui/.env.development rename to clients/admin-ui/.env.development index 7d83fda2ad..160c4e57e7 100644 --- a/clients/ctl/admin-ui/.env.development +++ b/clients/admin-ui/.env.development @@ -1,2 +1,3 @@ +NEXT_PUBLIC_FIDESOPS_API=http://0.0.0.0:8080 NEXT_PUBLIC_FIDESCTL_API=/api/v1 NEXT_PUBLIC_FIDESCTL_API_SERVER=http://0.0.0.0:8080 diff --git a/clients/ctl/admin-ui/.env.production b/clients/admin-ui/.env.production similarity index 100% rename from clients/ctl/admin-ui/.env.production rename to clients/admin-ui/.env.production diff --git a/clients/admin-ui/.eslintignore b/clients/admin-ui/.eslintignore new file mode 100644 index 0000000000..acaeb30a90 --- /dev/null +++ b/clients/admin-ui/.eslintignore @@ -0,0 +1,5 @@ +node_modules +dist +.eslintrc.json +next.config.js +jest.config.js \ No newline at end of file diff --git a/clients/ctl/admin-ui/.eslintrc.json b/clients/admin-ui/.eslintrc.json similarity index 84% rename from clients/ctl/admin-ui/.eslintrc.json rename to clients/admin-ui/.eslintrc.json index 33ea3b8ca6..4ad04f5aa8 100644 --- a/clients/ctl/admin-ui/.eslintrc.json +++ b/clients/admin-ui/.eslintrc.json @@ -8,7 +8,8 @@ "plugins": ["simple-import-sort"], "root": true, "parserOptions": { - "project": "./tsconfig.json" + "project": "tsconfig.json", + "tsconfigRootDir": "./" }, "rules": { // causes bug in re-exporting default exports, see @@ -23,14 +24,10 @@ "react/jsx-filename-extension": [ 1, { - "extensions": [ - ".tsx" - ] + "extensions": [".tsx"] } ], - "react/jsx-props-no-spreading": [ - 0 - ], + "react/jsx-props-no-spreading": [0], "simple-import-sort/imports": "error", "simple-import-sort/exports": "error", // since we are using static site export @@ -42,12 +39,10 @@ "error", { "props": true, - "ignorePropertyModificationsForRegex": [ - "^draft" - ] + "ignorePropertyModificationsForRegex": ["^draft"] } ], // Default exports are slightly preferred for component files, but this rule has too many false positives. "import/prefer-default-export": "off" } -} \ No newline at end of file +} diff --git a/clients/ctl/admin-ui/.gitignore b/clients/admin-ui/.gitignore similarity index 99% rename from clients/ctl/admin-ui/.gitignore rename to clients/admin-ui/.gitignore index 4e6c1c97e6..1ab82d7892 100644 --- a/clients/ctl/admin-ui/.gitignore +++ b/clients/admin-ui/.gitignore @@ -107,3 +107,6 @@ dist # msw web worker script public/mockServiceWorker.js + + +out/ \ No newline at end of file diff --git a/clients/admin-ui/.prettierignore b/clients/admin-ui/.prettierignore new file mode 100644 index 0000000000..36fcd514b4 --- /dev/null +++ b/clients/admin-ui/.prettierignore @@ -0,0 +1,4 @@ +.idea/ +.next/ +node_modules/ +out/ \ No newline at end of file diff --git a/clients/admin-ui/.prettierrc.json b/clients/admin-ui/.prettierrc.json new file mode 100644 index 0000000000..805e2f196e --- /dev/null +++ b/clients/admin-ui/.prettierrc.json @@ -0,0 +1,4 @@ +{ + "tabWidth": 2, + "endOfLine": "lf" +} diff --git a/clients/ctl/admin-ui/LICENSE b/clients/admin-ui/LICENSE similarity index 100% rename from clients/ctl/admin-ui/LICENSE rename to clients/admin-ui/LICENSE diff --git a/clients/admin-ui/README.md b/clients/admin-ui/README.md new file mode 100644 index 0000000000..d1e70d6820 --- /dev/null +++ b/clients/admin-ui/README.md @@ -0,0 +1,54 @@ +# Admin UI + +Admin UI for managing Fides privacy requests. A web application built in Next.js with the FidesUI component library. + +## Running Locally + +1. Run `nox -s create_user` and follow prompts to create a user. Note that password requires 8 or more characters, upper and lowercase chars, a number, and a symbol. +2. In a new shell, `cd` into `clients/ops/admin-ui`, then run `npm run dev`. +3. Nav to `http://localhost:3000/` and logged in using created user. The `email` field is simply the `user` that was created, not a valid email address. + +## Testing Entire Request Flow + +1. Run the fides server with `nox -s dev`. +2. Create a policy key through the API (using the Postman collection). +3. Configure the `clients/privacy-center` application to use that policy by adding it to the appropriate request config in `config/config.json`. +4. Run the Privacy Request center using `npm run dev`. +5. Submit a privacy request through the Privacy Request center. +6. View that request in the Admin UI and either approve or deny it. + +## Unit test locations + +Unless otherwise specified below, all unit tests should be colocated in the directory with the file(s) they are testing, in a `__tests__` subfolder. + +The sole exception to this is the `pages` directory. Tests for Next.js pages live in the root `__tests__/pages` directory. Otherwise, Next.js attempts to include them in final build output, which breaks the build. + +## Feature flags +During the software development process, one or more features may not be visible at runtime. To toggle a given feature, find the given feature flag `name` key located in the [flags.json](/clients/admin-ui/srcgs.json) file. Update the `isActive` key value to `true/false`. If `true`, feature will be visible at runtime. Otherwise, feature will not be visible at runtime. + +For techinical reference implementation, please reference [react-feature-flags](https://github.com/romaindso/react-feature-flags). + + + + + + +# FidesCtl Readme +# Admin UI + +Admin UI for managing Fidesctl. + +## Running Locally + +1. Run `nox -s dev` in top-level `fides` directory +1. Navigate to `http://localhost:3000/`. + +## Preparing for production + +To view a production version of this site, including the backend: + +1. Run `npm prod-export`. This will + 1. Export the static site to `out/` + 1. Copy the build from `out/` to the folder in the backend which will serve static assets at `/` +1. Run `nox -s api` in the top-level `fides` directory. +1. Navigate to `http://localhost:8000` diff --git a/clients/ctl/admin-ui/__tests__/checkbox-tree.test.tsx b/clients/admin-ui/__tests__/checkbox-tree.test.tsx similarity index 100% rename from clients/ctl/admin-ui/__tests__/checkbox-tree.test.tsx rename to clients/admin-ui/__tests__/checkbox-tree.test.tsx diff --git a/clients/ctl/admin-ui/__tests__/features/common/zones/config.test.ts b/clients/admin-ui/__tests__/features/common/zones/config.test.ts similarity index 100% rename from clients/ctl/admin-ui/__tests__/features/common/zones/config.test.ts rename to clients/admin-ui/__tests__/features/common/zones/config.test.ts diff --git a/clients/ctl/admin-ui/__tests__/features/dataset-helpers.test.tsx b/clients/admin-ui/__tests__/features/dataset-helpers.test.tsx similarity index 100% rename from clients/ctl/admin-ui/__tests__/features/dataset-helpers.test.tsx rename to clients/admin-ui/__tests__/features/dataset-helpers.test.tsx diff --git a/clients/ctl/admin-ui/__tests__/features/taxonomy-helpers.test.tsx b/clients/admin-ui/__tests__/features/taxonomy-helpers.test.tsx similarity index 100% rename from clients/ctl/admin-ui/__tests__/features/taxonomy-helpers.test.tsx rename to clients/admin-ui/__tests__/features/taxonomy-helpers.test.tsx diff --git a/clients/ctl/admin-ui/__tests__/features/taxonomy-transform.test.tsx b/clients/admin-ui/__tests__/features/taxonomy-transform.test.tsx similarity index 100% rename from clients/ctl/admin-ui/__tests__/features/taxonomy-transform.test.tsx rename to clients/admin-ui/__tests__/features/taxonomy-transform.test.tsx diff --git a/clients/admin-ui/__tests__/index.test.tsx b/clients/admin-ui/__tests__/index.test.tsx new file mode 100644 index 0000000000..f1b3cd9286 --- /dev/null +++ b/clients/admin-ui/__tests__/index.test.tsx @@ -0,0 +1,34 @@ +import Home from "../src/pages"; +import { mockNextUseRouter, render, screen } from "./test-utils"; + +describe("Home", () => { + it("renders the Subject Requests page by default when logged in", () => { + mockNextUseRouter({ route: "/" }); + render(, { + preloadedState: { + auth: { + user: { + username: "Test", + }, + token: "valid-token", + }, + }, + }); + + const message = screen.getAllByText("Subject Requests")[0]; + expect(message).toBeInTheDocument(); + }); + + // TODO: Either update or remove this test. We no longer use the SessionProvider from next/auth + // skip until this is fixed in fidesops + // it.skip("renders a logged out notification when no session is present", () => { + // render( + // + // + // + // ); + // + // const message = screen.getByText("You are not logged in."); + // expect(message).toBeInTheDocument(); + // }); +}); diff --git a/clients/ctl/admin-ui/__tests__/jest.setup.ts b/clients/admin-ui/__tests__/jest.setup.ts similarity index 100% rename from clients/ctl/admin-ui/__tests__/jest.setup.ts rename to clients/admin-ui/__tests__/jest.setup.ts diff --git a/clients/admin-ui/__tests__/pages/datastore-connection/index.test.tsx b/clients/admin-ui/__tests__/pages/datastore-connection/index.test.tsx new file mode 100644 index 0000000000..a2abfd9f02 --- /dev/null +++ b/clients/admin-ui/__tests__/pages/datastore-connection/index.test.tsx @@ -0,0 +1,68 @@ +import { rest } from "msw"; +import { setupServer } from "msw/node"; + +import { + BASE_URL, + CONNECTION_ROUTE, + DATASTORE_CONNECTION_ROUTE, + LOGIN_ROUTE, +} from "../../../src/constants"; +import DatastoreConnection from "../../../src/pages/datastore-connection"; +import { act, render, waitFor } from "../../test-utils"; + +const useRouter = jest.spyOn(require("next/router"), "useRouter"); + +afterAll(() => { + useRouter.mockRestore(); +}); + +describe(`${DATASTORE_CONNECTION_ROUTE}`, () => { + describe("Auth behavior", () => { + it("Should redirect to LoginPage when user isn't logged in.", async () => { + const push = jest.fn(); + useRouter.mockImplementation(() => ({ + push, + })); + + await act(async () => { + render(); + }); + + await waitFor(() => expect(push).toHaveBeenCalledTimes(1)); + expect(push).toHaveBeenCalledWith(LOGIN_ROUTE); + }); + + it.skip(`Should stay on DatastoreConnectionPage when the user is already logged in`, async () => { + await act(async () => { + const push = jest.fn(); + + useRouter.mockImplementation(() => ({ + pathname: "", + push, + prefetch: jest.fn(() => Promise.resolve()), + })); + const server = setupServer( + rest.get(`${BASE_URL}${CONNECTION_ROUTE}`, (req, res) => res()) + ); + + server.listen(); + + await act(async () => { + render(, { + preloadedState: { + auth: { + user: { + username: "Test User", + }, + token: "valid-token", + }, + }, + }); + }); + + expect(push).toHaveBeenCalledTimes(0); + server.close(); + }); + }); + }); +}); diff --git a/clients/admin-ui/__tests__/pages/login.test.tsx b/clients/admin-ui/__tests__/pages/login.test.tsx new file mode 100644 index 0000000000..40bcc4e89c --- /dev/null +++ b/clients/admin-ui/__tests__/pages/login.test.tsx @@ -0,0 +1,86 @@ +import { rest } from "msw"; +import { setupServer } from "msw/node"; + +import { BASE_API_URN, INDEX_ROUTE } from "../../src/constants"; +import LoginPage from "../../src/pages/login"; +import { act, fireEvent, render, screen, waitFor } from "../test-utils"; + +const useRouter = jest.spyOn(require("next/router"), "useRouter"); + +afterAll(() => { + useRouter.mockRestore(); +}); + +describe("/login", () => { + it("Should redirect when the user logs in successfully", async () => { + const server = setupServer( + rest.post(`${BASE_API_URN}/login`, (req, res, ctx) => + res( + ctx.json({ + user_data: { + username: "Test", + }, + token_data: { + access_token: "test-access-token", + }, + }) + ) + ) + ); + + server.listen(); + + const push = jest.fn(); + useRouter.mockImplementation(() => ({ + push, + })); + + await act(async () => { + render(); + }); + + expect(push).toBeCalledTimes(0); + + const email = screen.getByRole("textbox", { name: /email/i }); + const passwordInput = screen.getByLabelText(/password/i); + const loginButton = screen.getByRole("button"); + + await act(async () => { + await fireEvent.change(email, { target: { value: "test-user" } }); + await fireEvent.change(passwordInput, { + target: { value: "test-user-password" }, + }); + await fireEvent.submit(loginButton); + }); + + await waitFor(() => expect(push).toHaveBeenCalledTimes(1)); + expect(push).toHaveBeenCalledWith(INDEX_ROUTE); + + server.close(); + }); + + it(`Should redirect to "${INDEX_ROUTE}" when the user is already logged in`, async () => { + await act(async () => { + const push = jest.fn(); + useRouter.mockImplementation(() => ({ + push, + })); + + await act(async () => { + render(, { + preloadedState: { + auth: { + user: { + username: "Test User", + }, + token: "valid-token", + }, + }, + }); + }); + + expect(push).toHaveBeenCalledWith(INDEX_ROUTE); + expect(push).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/clients/admin-ui/__tests__/test-utils.tsx b/clients/admin-ui/__tests__/test-utils.tsx new file mode 100644 index 0000000000..08342d738a --- /dev/null +++ b/clients/admin-ui/__tests__/test-utils.tsx @@ -0,0 +1,59 @@ +// test-utils.jsx +import { Store } from "@reduxjs/toolkit"; +import { render as rtlRender, RenderOptions } from "@testing-library/react"; +import React from "react"; +import { Provider } from "react-redux"; + +import { makeStore, RootState } from "~/app/store"; + +type CustomRenderOptions = { + preloadedState?: Partial; + customStore?: Store; +} & RenderOptions; + +function render( + ui: React.ReactElement>, + { + preloadedState, + customStore = makeStore(preloadedState), + ...renderOptions + }: CustomRenderOptions = {} +) { + const Wrapper: React.FC = ({ children }) => ( + {children} + ); + return rtlRender(ui, { wrapper: Wrapper, ...renderOptions }); +} + +// re-export everything +export * from "@testing-library/react"; + +// override render method +export { render }; + +// Mocks useRouter +const useRouter = jest.spyOn(require("next/router"), "useRouter"); + +/** + * mockNextUseRouter + * Mocks the useRouter React hook from Next.js on a test-case by test-case basis + * Adapted from https://github.com/vercel/next.js/issues/7479#issuecomment-587145429 + */ +export function mockNextUseRouter({ + route = "/", + pathname = "/", + query = "/", + asPath = "/", +}: { + route?: string; + pathname?: string; + query?: string; + asPath?: string; +}) { + useRouter.mockImplementation(() => ({ + route, + pathname, + query, + asPath, + })); +} diff --git a/clients/ctl/admin-ui/cypress.config.ts b/clients/admin-ui/cypress.config.ts similarity index 100% rename from clients/ctl/admin-ui/cypress.config.ts rename to clients/admin-ui/cypress.config.ts diff --git a/clients/ctl/admin-ui/cypress/.eslintrc.json b/clients/admin-ui/cypress/.eslintrc.json similarity index 100% rename from clients/ctl/admin-ui/cypress/.eslintrc.json rename to clients/admin-ui/cypress/.eslintrc.json diff --git a/clients/ctl/admin-ui/cypress/.gitignore b/clients/admin-ui/cypress/.gitignore similarity index 100% rename from clients/ctl/admin-ui/cypress/.gitignore rename to clients/admin-ui/cypress/.gitignore diff --git a/clients/ctl/admin-ui/cypress/e2e/config-wizard.cy.ts b/clients/admin-ui/cypress/e2e/config-wizard.cy.ts similarity index 100% rename from clients/ctl/admin-ui/cypress/e2e/config-wizard.cy.ts rename to clients/admin-ui/cypress/e2e/config-wizard.cy.ts diff --git a/clients/ctl/admin-ui/cypress/e2e/datasets-classify.cy.ts b/clients/admin-ui/cypress/e2e/datasets-classify.cy.ts similarity index 100% rename from clients/ctl/admin-ui/cypress/e2e/datasets-classify.cy.ts rename to clients/admin-ui/cypress/e2e/datasets-classify.cy.ts diff --git a/clients/ctl/admin-ui/cypress/e2e/datasets.cy.ts b/clients/admin-ui/cypress/e2e/datasets.cy.ts similarity index 99% rename from clients/ctl/admin-ui/cypress/e2e/datasets.cy.ts rename to clients/admin-ui/cypress/e2e/datasets.cy.ts index fc32f217a4..e371a00442 100644 --- a/clients/ctl/admin-ui/cypress/e2e/datasets.cy.ts +++ b/clients/admin-ui/cypress/e2e/datasets.cy.ts @@ -5,6 +5,10 @@ import { } from "cypress/support/stubs"; describe("Dataset", () => { + before(() => { + cy.login(); + }); + beforeEach(() => { stubDatasetCrud(); // Ensure these tests all run with Plus features disabled. diff --git a/clients/ctl/admin-ui/cypress/e2e/nav-bar.cy.ts b/clients/admin-ui/cypress/e2e/nav-bar.cy.ts similarity index 81% rename from clients/ctl/admin-ui/cypress/e2e/nav-bar.cy.ts rename to clients/admin-ui/cypress/e2e/nav-bar.cy.ts index 72d93f19bb..979bf6caf1 100644 --- a/clients/ctl/admin-ui/cypress/e2e/nav-bar.cy.ts +++ b/clients/admin-ui/cypress/e2e/nav-bar.cy.ts @@ -1,12 +1,17 @@ describe("Nav Bar", () => { + before(() => { + cy.login(); + }); + it("Renders all page links", () => { cy.visit("/"); - // Enabled links + cy.getByTestId("nav-link-Subject Requests"); + cy.getByTestId("nav-link-Datastore Connections"); + cy.getByTestId("nav-link-User Management"); cy.getByTestId("nav-link-Datasets"); cy.getByTestId("nav-link-Taxonomy"); cy.getByTestId("nav-link-Systems"); - }); it("Renders the active page based on the current route", () => { diff --git a/clients/ctl/admin-ui/cypress/e2e/systems.cy.ts b/clients/admin-ui/cypress/e2e/systems.cy.ts similarity index 99% rename from clients/ctl/admin-ui/cypress/e2e/systems.cy.ts rename to clients/admin-ui/cypress/e2e/systems.cy.ts index fa058e2811..b7bf993c12 100644 --- a/clients/ctl/admin-ui/cypress/e2e/systems.cy.ts +++ b/clients/admin-ui/cypress/e2e/systems.cy.ts @@ -1,6 +1,9 @@ import { stubSystemCrud, stubTaxonomyEntities } from "../support/stubs"; describe("System management page", () => { + before(() => { + cy.login(); + }); beforeEach(() => { cy.intercept("GET", "/api/v1/system", { fixture: "systems.json" }).as( "getSystems" diff --git a/clients/ctl/admin-ui/cypress/e2e/taxonomy.cy.ts b/clients/admin-ui/cypress/e2e/taxonomy.cy.ts similarity index 99% rename from clients/ctl/admin-ui/cypress/e2e/taxonomy.cy.ts rename to clients/admin-ui/cypress/e2e/taxonomy.cy.ts index 05209a6a53..2a4820f2e8 100644 --- a/clients/ctl/admin-ui/cypress/e2e/taxonomy.cy.ts +++ b/clients/admin-ui/cypress/e2e/taxonomy.cy.ts @@ -1,4 +1,8 @@ describe("Taxonomy management page", () => { + before(() => { + cy.login(); + }); + beforeEach(() => { cy.intercept("GET", "/api/v1/data_category", { fixture: "data_categories.json", diff --git a/clients/admin-ui/cypress/fixtures/classification/create.json b/clients/admin-ui/cypress/fixtures/classification/create.json new file mode 100644 index 0000000000..0ef5a016e1 --- /dev/null +++ b/clients/admin-ui/cypress/fixtures/classification/create.json @@ -0,0 +1,5 @@ +{ + "id": "classification-response", + "fides_key": "demo_users_dataset", + "status": "processing" +} diff --git a/clients/admin-ui/cypress/fixtures/classification/list.json b/clients/admin-ui/cypress/fixtures/classification/list.json new file mode 100644 index 0000000000..027ea4bca8 --- /dev/null +++ b/clients/admin-ui/cypress/fixtures/classification/list.json @@ -0,0 +1,45 @@ +[ + { + "id": "2", + "fides_key": "demo_users_dataset_2", + "status": "processing" + }, + { + "id": "3", + "fides_key": "demo_users_dataset_3", + "status": "review", + "classification": { + "data_categories": ["user"], + "collections": [ + { + "name": "users", + "fields": [ + { + "name": "device", + "data_categories": ["user.device"] + } + ] + } + ] + } + }, + { + "id": "4", + "fides_key": "demo_users_dataset_4", + "status": "classified", + "classification": { + "data_categories": ["user"], + "collections": [ + { + "name": "users", + "fields": [ + { + "name": "device", + "data_categories": ["user.device"] + } + ] + } + ] + } + } +] diff --git a/clients/ctl/admin-ui/cypress/fixtures/classify/create.json b/clients/admin-ui/cypress/fixtures/classify/create.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/classify/create.json rename to clients/admin-ui/cypress/fixtures/classify/create.json diff --git a/clients/ctl/admin-ui/cypress/fixtures/classify/dataset-in-review.json b/clients/admin-ui/cypress/fixtures/classify/dataset-in-review.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/classify/dataset-in-review.json rename to clients/admin-ui/cypress/fixtures/classify/dataset-in-review.json diff --git a/clients/ctl/admin-ui/cypress/fixtures/classify/get-in-review.json b/clients/admin-ui/cypress/fixtures/classify/get-in-review.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/classify/get-in-review.json rename to clients/admin-ui/cypress/fixtures/classify/get-in-review.json diff --git a/clients/ctl/admin-ui/cypress/fixtures/classify/list.json b/clients/admin-ui/cypress/fixtures/classify/list.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/classify/list.json rename to clients/admin-ui/cypress/fixtures/classify/list.json diff --git a/clients/ctl/admin-ui/cypress/fixtures/classify/update.json b/clients/admin-ui/cypress/fixtures/classify/update.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/classify/update.json rename to clients/admin-ui/cypress/fixtures/classify/update.json diff --git a/clients/ctl/admin-ui/cypress/fixtures/data_categories.json b/clients/admin-ui/cypress/fixtures/data_categories.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/data_categories.json rename to clients/admin-ui/cypress/fixtures/data_categories.json diff --git a/clients/ctl/admin-ui/cypress/fixtures/data_qualifiers.json b/clients/admin-ui/cypress/fixtures/data_qualifiers.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/data_qualifiers.json rename to clients/admin-ui/cypress/fixtures/data_qualifiers.json diff --git a/clients/ctl/admin-ui/cypress/fixtures/data_subjects.json b/clients/admin-ui/cypress/fixtures/data_subjects.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/data_subjects.json rename to clients/admin-ui/cypress/fixtures/data_subjects.json diff --git a/clients/ctl/admin-ui/cypress/fixtures/data_uses.json b/clients/admin-ui/cypress/fixtures/data_uses.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/data_uses.json rename to clients/admin-ui/cypress/fixtures/data_uses.json diff --git a/clients/ctl/admin-ui/cypress/fixtures/dataset.json b/clients/admin-ui/cypress/fixtures/dataset.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/dataset.json rename to clients/admin-ui/cypress/fixtures/dataset.json diff --git a/clients/ctl/admin-ui/cypress/fixtures/datasets.json b/clients/admin-ui/cypress/fixtures/datasets.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/datasets.json rename to clients/admin-ui/cypress/fixtures/datasets.json diff --git a/clients/ctl/admin-ui/cypress/fixtures/generate/dataset.json b/clients/admin-ui/cypress/fixtures/generate/dataset.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/generate/dataset.json rename to clients/admin-ui/cypress/fixtures/generate/dataset.json diff --git a/clients/ctl/admin-ui/cypress/fixtures/generate/system.json b/clients/admin-ui/cypress/fixtures/generate/system.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/generate/system.json rename to clients/admin-ui/cypress/fixtures/generate/system.json diff --git a/clients/admin-ui/cypress/fixtures/login.json b/clients/admin-ui/cypress/fixtures/login.json new file mode 100644 index 0000000000..d6db3817b0 --- /dev/null +++ b/clients/admin-ui/cypress/fixtures/login.json @@ -0,0 +1,12 @@ +{ + "user_data": { + "id": "123", + "username": "cypress-user@ethyca.com", + "created_at": "2022-09-28T16:15:30.994Z", + "first_name": "Cypress", + "last_name": "User" + }, + "token_data": { + "access_token": "super_secret" + } +} diff --git a/clients/ctl/admin-ui/cypress/fixtures/organization.json b/clients/admin-ui/cypress/fixtures/organization.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/organization.json rename to clients/admin-ui/cypress/fixtures/organization.json diff --git a/clients/ctl/admin-ui/cypress/fixtures/system.json b/clients/admin-ui/cypress/fixtures/system.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/system.json rename to clients/admin-ui/cypress/fixtures/system.json diff --git a/clients/ctl/admin-ui/cypress/fixtures/systems.json b/clients/admin-ui/cypress/fixtures/systems.json similarity index 100% rename from clients/ctl/admin-ui/cypress/fixtures/systems.json rename to clients/admin-ui/cypress/fixtures/systems.json diff --git a/clients/ctl/admin-ui/cypress/support/commands.ts b/clients/admin-ui/cypress/support/commands.ts similarity index 61% rename from clients/ctl/admin-ui/cypress/support/commands.ts rename to clients/admin-ui/cypress/support/commands.ts index f3ff1d1212..0be9973e73 100644 --- a/clients/ctl/admin-ui/cypress/support/commands.ts +++ b/clients/admin-ui/cypress/support/commands.ts @@ -1,9 +1,24 @@ /// +import { STORAGE_ROOT_KEY } from "~/constants"; + Cypress.Commands.add("getByTestId", (selector, ...args) => cy.get(`[data-testid='${selector}']`, ...args) ); +Cypress.Commands.add("login", () => { + cy.fixture("login.json").then((body) => { + const authState = { + user_data: body.user_data, + token: body.token_data.access_token, + }; + window.localStorage.setItem( + STORAGE_ROOT_KEY, + JSON.stringify(authState) + ); + }); +}); + declare global { namespace Cypress { interface Chainable { @@ -20,6 +35,10 @@ declare global { Cypress.Shadow > ): Chainable>; + /** + * Programmatically login with a mock user + */ + login(): void; } } } diff --git a/clients/ctl/admin-ui/cypress/support/component-index.html b/clients/admin-ui/cypress/support/component-index.html similarity index 100% rename from clients/ctl/admin-ui/cypress/support/component-index.html rename to clients/admin-ui/cypress/support/component-index.html diff --git a/clients/ctl/admin-ui/cypress/support/component.ts b/clients/admin-ui/cypress/support/component.ts similarity index 100% rename from clients/ctl/admin-ui/cypress/support/component.ts rename to clients/admin-ui/cypress/support/component.ts diff --git a/clients/ctl/admin-ui/cypress/support/e2e.ts b/clients/admin-ui/cypress/support/e2e.ts similarity index 100% rename from clients/ctl/admin-ui/cypress/support/e2e.ts rename to clients/admin-ui/cypress/support/e2e.ts diff --git a/clients/ctl/admin-ui/cypress/support/stubs.ts b/clients/admin-ui/cypress/support/stubs.ts similarity index 100% rename from clients/ctl/admin-ui/cypress/support/stubs.ts rename to clients/admin-ui/cypress/support/stubs.ts diff --git a/clients/ctl/admin-ui/cypress/tsconfig.json b/clients/admin-ui/cypress/tsconfig.json similarity index 100% rename from clients/ctl/admin-ui/cypress/tsconfig.json rename to clients/admin-ui/cypress/tsconfig.json diff --git a/clients/ctl/admin-ui/jest.config.js b/clients/admin-ui/jest.config.js similarity index 74% rename from clients/ctl/admin-ui/jest.config.js rename to clients/admin-ui/jest.config.js index 515f0f6706..25d18dfc93 100644 --- a/clients/ctl/admin-ui/jest.config.js +++ b/clients/admin-ui/jest.config.js @@ -19,6 +19,13 @@ module.exports = { // Handle module aliases "^@/components/(.*)$": "/components/$1", + "^common/(.*)$": "/src/features/common/$1", + "^connection-type/(.*)$": "/src/features/connection-type/$1", + "^datastore-connections/(.*)$": + "/src/features/datastore-connections/$1", + "^privacy-requests/(.*)$": "/src/features/privacy-requests/$1", + "^subject-request/(.*)$": "/src/features/subject-request/$1", + "^user-management/(.*)$": "/src/features/user-management/$1", "^~/(.*)$": "/src/$1", }, // Add more setup options before each test is run @@ -27,6 +34,7 @@ module.exports = { "/node_modules/", "/.next/", "jest.setup.ts", + "test-utils.tsx", ], testEnvironment: "jsdom", transform: { diff --git a/clients/ctl/admin-ui/next-env.d.ts b/clients/admin-ui/next-env.d.ts similarity index 100% rename from clients/ctl/admin-ui/next-env.d.ts rename to clients/admin-ui/next-env.d.ts diff --git a/clients/admin-ui/next.config.js b/clients/admin-ui/next.config.js new file mode 100644 index 0000000000..5913b8d4cd --- /dev/null +++ b/clients/admin-ui/next.config.js @@ -0,0 +1,42 @@ +const path = require("path"); + +/** @type {import("next").NextConfig} */ +const withBundleAnalyzer = require("@next/bundle-analyzer")({ + enabled: process.env.ANALYZE === "true", +}); + +const nextConfig = { + reactStrictMode: true, + webpack(config) { + Object.assign(config.resolve.alias, { + react: path.resolve(__dirname, "node_modules", "react"), + "react-dom": path.resolve(__dirname, "node_modules", "react-dom"), + "@emotion/react": path.resolve( + __dirname, + "node_modules", + "@emotion/react" + ), + }); + + return config; + }, + async rewrites() { + // these paths are unnecessarily complicated due to our backend being + // picky about trailing slashes https://github.com/ethyca/fides/issues/690 + return [ + { + source: `/api/v1/:path`, + destination: `${process.env.NEXT_PUBLIC_FIDESCTL_API_SERVER}/api/v1/:path/`, + }, + { + source: `/api/v1/:first/:second*`, + destination: `${process.env.NEXT_PUBLIC_FIDESCTL_API_SERVER}/api/v1/:first/:second*`, + }, + ] + }, + images: { + loader: "custom", + }, +}; + +module.exports = withBundleAnalyzer(nextConfig); diff --git a/clients/ctl/admin-ui/package-lock.json b/clients/admin-ui/package-lock.json similarity index 91% rename from clients/ctl/admin-ui/package-lock.json rename to clients/admin-ui/package-lock.json index 83c4f67177..901a4d6d2f 100644 --- a/clients/ctl/admin-ui/package-lock.json +++ b/clients/admin-ui/package-lock.json @@ -1,23 +1,24 @@ { - "name": "ctl-admin-ui", + "name": "admin-ui", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "ctl-admin-ui", + "name": "admin-ui", "dependencies": { + "@chakra-ui/icons": "^1.1.7", "@chakra-ui/react": "^1.8.0", - "@chakra-ui/system": ">=1.0.0", - "@chakra-ui/utils": "^1.10.4", + "@chakra-ui/system": "^1.12.1", + "@chakra-ui/utils": "^2.0.9", "@emotion/react": "^11", "@emotion/styled": "^11", "@fidesui/react": "^0.0.12", "@fontsource/inter": "^4.5.4", + "@monaco-editor/react": "^4.4.5", "@reduxjs/toolkit": "^1.8.0", "chakra-react-select": "^3.3.7", "date-fns": "^2.28.0", "date-fns-tz": "^1.3.1", - "eslint-plugin-simple-import-sort": "^7.0.0", "formik": "^2.2.9", "framer-motion": "^5", "i18n-iso-countries": "^7.4.0", @@ -27,12 +28,13 @@ "msw": "^0.43.0", "narrow-minded": "^1.1.1", "next": "12.1.0", - "next-auth": "^4.10.3", "next-redux-wrapper": "^7.0.5", - "prettier": "^2.6.2", + "next-remove-imports": "^1.0.7", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-feature-flags": "^1.0.0", "react-redux": "^7.2.6", + "redux-persist": "^6.0.0", "whatwg-fetch": "^3.6.2", "yup": "^0.32.11" }, @@ -44,6 +46,7 @@ "@types/lodash.debounce": "^4.0.6", "@types/node": "17.0.10", "@types/react": "17.0.38", + "@types/react-redux": "^7.1.24", "@typescript-eslint/eslint-plugin": "^5.12.0", "@typescript-eslint/parser": "^5.12.0", "babel-jest": "^27.5.1", @@ -60,9 +63,11 @@ "eslint-plugin-no-only-tests": "^3.0.0", "eslint-plugin-react": "^7.28.0", "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-simple-import-sort": "^7.0.0", "identity-obj-proxy": "^3.0.0", "jest": "^27.5.1", "openapi-typescript-codegen": "^0.20.1", + "prettier": "^2.6.2", "typescript": "4.5.5" } }, @@ -78,9 +83,8 @@ }, "node_modules/@apidevtools/json-schema-ref-parser": { "version": "9.0.9", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", - "integrity": "sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==", "dev": true, + "license": "MIT", "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.6", @@ -339,7 +343,7 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.16.7", + "version": "7.19.0", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -558,6 +562,19 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", "dev": true, @@ -653,7 +670,7 @@ } }, "node_modules/@babel/runtime": { - "version": "7.16.7", + "version": "7.19.0", "license": "MIT", "dependencies": { "regenerator-runtime": "^0.13.4" @@ -945,19 +962,52 @@ } }, "node_modules/@chakra-ui/color-mode": { - "version": "1.4.1", + "version": "1.4.3", "license": "MIT", "dependencies": { - "@chakra-ui/hooks": "1.8.0", - "@chakra-ui/react-env": "1.1.2", - "@chakra-ui/utils": "1.10.0" + "@chakra-ui/hooks": "1.8.2", + "@chakra-ui/react-env": "1.1.4", + "@chakra-ui/utils": "1.10.2" + }, + "peerDependencies": { + "react": ">=16.8.6" + } + }, + "node_modules/@chakra-ui/color-mode/node_modules/@chakra-ui/hooks": { + "version": "1.8.2", + "license": "MIT", + "dependencies": { + "@chakra-ui/react-utils": "1.2.2", + "@chakra-ui/utils": "1.10.2", + "compute-scroll-into-view": "1.0.14", + "copy-to-clipboard": "3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.6" + } + }, + "node_modules/@chakra-ui/color-mode/node_modules/@chakra-ui/react-env": { + "version": "1.1.4", + "license": "MIT", + "dependencies": { + "@chakra-ui/utils": "1.10.2" + }, + "peerDependencies": { + "react": ">=16.8.6" + } + }, + "node_modules/@chakra-ui/color-mode/node_modules/@chakra-ui/react-utils": { + "version": "1.2.2", + "license": "MIT", + "dependencies": { + "@chakra-ui/utils": "^1.10.2" }, "peerDependencies": { "react": ">=16.8.6" } }, "node_modules/@chakra-ui/color-mode/node_modules/@chakra-ui/utils": { - "version": "1.10.0", + "version": "1.10.2", "license": "MIT", "dependencies": { "@types/lodash.mergewith": "4.6.6", @@ -1138,6 +1188,39 @@ "lodash.mergewith": "4.6.2" } }, + "node_modules/@chakra-ui/icons": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "@chakra-ui/icon": "2.0.5", + "@types/react": "^17.0.15" + }, + "peerDependencies": { + "@chakra-ui/system": ">=1.0.0", + "react": ">=16.8.6" + } + }, + "node_modules/@chakra-ui/icons/node_modules/@chakra-ui/icon": { + "version": "2.0.5", + "license": "MIT", + "dependencies": { + "@chakra-ui/utils": "1.10.4" + }, + "peerDependencies": { + "@chakra-ui/system": ">=1.0.0", + "react": ">=16.8.6" + } + }, + "node_modules/@chakra-ui/icons/node_modules/@chakra-ui/utils": { + "version": "1.10.4", + "license": "MIT", + "dependencies": { + "@types/lodash.mergewith": "4.6.6", + "css-box-model": "1.2.1", + "framesync": "5.3.0", + "lodash.mergewith": "4.6.2" + } + }, "node_modules/@chakra-ui/image": { "version": "1.1.3", "license": "MIT", @@ -1458,6 +1541,42 @@ "react-dom": ">=16.8.6" } }, + "node_modules/@chakra-ui/provider/node_modules/@chakra-ui/color-mode": { + "version": "1.4.1", + "license": "MIT", + "dependencies": { + "@chakra-ui/hooks": "1.8.0", + "@chakra-ui/react-env": "1.1.2", + "@chakra-ui/utils": "1.10.0" + }, + "peerDependencies": { + "react": ">=16.8.6" + } + }, + "node_modules/@chakra-ui/provider/node_modules/@chakra-ui/styled-system": { + "version": "1.17.0", + "license": "MIT", + "dependencies": { + "@chakra-ui/utils": "1.10.0", + "csstype": "^3.0.9" + } + }, + "node_modules/@chakra-ui/provider/node_modules/@chakra-ui/system": { + "version": "1.10.1", + "license": "MIT", + "dependencies": { + "@chakra-ui/color-mode": "1.4.1", + "@chakra-ui/react-utils": "1.2.1", + "@chakra-ui/styled-system": "1.17.0", + "@chakra-ui/utils": "1.10.0", + "react-fast-compare": "3.2.0" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0", + "@emotion/styled": "^11.0.0", + "react": ">=16.8.6" + } + }, "node_modules/@chakra-ui/provider/node_modules/@chakra-ui/utils": { "version": "1.10.0", "license": "MIT", @@ -1583,6 +1702,52 @@ "react": ">=16.8.6" } }, + "node_modules/@chakra-ui/react-utils/node_modules/@chakra-ui/utils": { + "version": "1.10.4", + "license": "MIT", + "dependencies": { + "@types/lodash.mergewith": "4.6.6", + "css-box-model": "1.2.1", + "framesync": "5.3.0", + "lodash.mergewith": "4.6.2" + } + }, + "node_modules/@chakra-ui/react/node_modules/@chakra-ui/color-mode": { + "version": "1.4.1", + "license": "MIT", + "dependencies": { + "@chakra-ui/hooks": "1.8.0", + "@chakra-ui/react-env": "1.1.2", + "@chakra-ui/utils": "1.10.0" + }, + "peerDependencies": { + "react": ">=16.8.6" + } + }, + "node_modules/@chakra-ui/react/node_modules/@chakra-ui/styled-system": { + "version": "1.17.0", + "license": "MIT", + "dependencies": { + "@chakra-ui/utils": "1.10.0", + "csstype": "^3.0.9" + } + }, + "node_modules/@chakra-ui/react/node_modules/@chakra-ui/system": { + "version": "1.10.1", + "license": "MIT", + "dependencies": { + "@chakra-ui/color-mode": "1.4.1", + "@chakra-ui/react-utils": "1.2.1", + "@chakra-ui/styled-system": "1.17.0", + "@chakra-ui/utils": "1.10.0", + "react-fast-compare": "3.2.0" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0", + "@emotion/styled": "^11.0.0", + "react": ">=16.8.6" + } + }, "node_modules/@chakra-ui/react/node_modules/@chakra-ui/utils": { "version": "1.10.0", "license": "MIT", @@ -1628,6 +1793,42 @@ "react": ">=16.8.6" } }, + "node_modules/@chakra-ui/skeleton/node_modules/@chakra-ui/color-mode": { + "version": "1.4.1", + "license": "MIT", + "dependencies": { + "@chakra-ui/hooks": "1.8.0", + "@chakra-ui/react-env": "1.1.2", + "@chakra-ui/utils": "1.10.0" + }, + "peerDependencies": { + "react": ">=16.8.6" + } + }, + "node_modules/@chakra-ui/skeleton/node_modules/@chakra-ui/styled-system": { + "version": "1.17.0", + "license": "MIT", + "dependencies": { + "@chakra-ui/utils": "1.10.0", + "csstype": "^3.0.9" + } + }, + "node_modules/@chakra-ui/skeleton/node_modules/@chakra-ui/system": { + "version": "1.10.1", + "license": "MIT", + "dependencies": { + "@chakra-ui/color-mode": "1.4.1", + "@chakra-ui/react-utils": "1.2.1", + "@chakra-ui/styled-system": "1.17.0", + "@chakra-ui/utils": "1.10.0", + "react-fast-compare": "3.2.0" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0", + "@emotion/styled": "^11.0.0", + "react": ">=16.8.6" + } + }, "node_modules/@chakra-ui/skeleton/node_modules/@chakra-ui/utils": { "version": "1.10.0", "license": "MIT", @@ -1707,15 +1908,15 @@ } }, "node_modules/@chakra-ui/styled-system": { - "version": "1.17.0", + "version": "1.17.2", "license": "MIT", "dependencies": { - "@chakra-ui/utils": "1.10.0", + "@chakra-ui/utils": "1.10.2", "csstype": "^3.0.9" } }, "node_modules/@chakra-ui/styled-system/node_modules/@chakra-ui/utils": { - "version": "1.10.0", + "version": "1.10.2", "license": "MIT", "dependencies": { "@types/lodash.mergewith": "4.6.6", @@ -1747,13 +1948,13 @@ } }, "node_modules/@chakra-ui/system": { - "version": "1.10.1", + "version": "1.12.1", "license": "MIT", "dependencies": { - "@chakra-ui/color-mode": "1.4.1", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/styled-system": "1.17.0", - "@chakra-ui/utils": "1.10.0", + "@chakra-ui/color-mode": "1.4.8", + "@chakra-ui/react-utils": "1.2.3", + "@chakra-ui/styled-system": "1.19.0", + "@chakra-ui/utils": "1.10.4", "react-fast-compare": "3.2.0" }, "peerDependencies": { @@ -1762,8 +1963,61 @@ "react": ">=16.8.6" } }, + "node_modules/@chakra-ui/system/node_modules/@chakra-ui/color-mode": { + "version": "1.4.8", + "license": "MIT", + "dependencies": { + "@chakra-ui/hooks": "1.9.1", + "@chakra-ui/react-env": "1.1.6", + "@chakra-ui/utils": "1.10.4" + }, + "peerDependencies": { + "react": ">=16.8.6" + } + }, + "node_modules/@chakra-ui/system/node_modules/@chakra-ui/hooks": { + "version": "1.9.1", + "license": "MIT", + "dependencies": { + "@chakra-ui/react-utils": "1.2.3", + "@chakra-ui/utils": "1.10.4", + "compute-scroll-into-view": "1.0.14", + "copy-to-clipboard": "3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.6" + } + }, + "node_modules/@chakra-ui/system/node_modules/@chakra-ui/react-env": { + "version": "1.1.6", + "license": "MIT", + "dependencies": { + "@chakra-ui/utils": "1.10.4" + }, + "peerDependencies": { + "react": ">=16.8.6" + } + }, + "node_modules/@chakra-ui/system/node_modules/@chakra-ui/react-utils": { + "version": "1.2.3", + "license": "MIT", + "dependencies": { + "@chakra-ui/utils": "^1.10.4" + }, + "peerDependencies": { + "react": ">=16.8.6" + } + }, + "node_modules/@chakra-ui/system/node_modules/@chakra-ui/styled-system": { + "version": "1.19.0", + "license": "MIT", + "dependencies": { + "@chakra-ui/utils": "1.10.4", + "csstype": "3.0.9" + } + }, "node_modules/@chakra-ui/system/node_modules/@chakra-ui/utils": { - "version": "1.10.0", + "version": "1.10.4", "license": "MIT", "dependencies": { "@types/lodash.mergewith": "4.6.6", @@ -1772,6 +2026,10 @@ "lodash.mergewith": "4.6.2" } }, + "node_modules/@chakra-ui/system/node_modules/csstype": { + "version": "3.0.9", + "license": "MIT" + }, "node_modules/@chakra-ui/table": { "version": "1.3.2", "license": "MIT", @@ -1984,7 +2242,7 @@ } }, "node_modules/@chakra-ui/utils": { - "version": "1.10.4", + "version": "2.0.9", "license": "MIT", "dependencies": { "@types/lodash.mergewith": "4.6.6", @@ -2101,16 +2359,16 @@ } }, "node_modules/@emotion/babel-plugin": { - "version": "11.7.2", + "version": "11.10.2", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.12.13", - "@babel/plugin-syntax-jsx": "^7.12.13", - "@babel/runtime": "^7.13.10", - "@emotion/hash": "^0.8.0", - "@emotion/memoize": "^0.7.5", - "@emotion/serialize": "^1.0.2", - "babel-plugin-macros": "^2.6.1", + "@babel/helper-module-imports": "^7.16.7", + "@babel/plugin-syntax-jsx": "^7.17.12", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/serialize": "^1.1.0", + "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", "find-root": "^1.1.0", @@ -2121,18 +2379,9 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@emotion/babel-plugin/node_modules/@babel/plugin-syntax-jsx": { - "version": "7.16.7", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } + "node_modules/@emotion/babel-plugin/node_modules/@emotion/memoize": { + "version": "0.8.0", + "license": "MIT" }, "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { "version": "1.8.0", @@ -2149,20 +2398,24 @@ } }, "node_modules/@emotion/cache": { - "version": "11.9.3", + "version": "11.10.3", "license": "MIT", "dependencies": { - "@emotion/memoize": "^0.7.4", - "@emotion/sheet": "^1.1.1", - "@emotion/utils": "^1.0.0", - "@emotion/weak-memoize": "^0.2.5", + "@emotion/memoize": "^0.8.0", + "@emotion/sheet": "^1.2.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", "stylis": "4.0.13" } }, - "node_modules/@emotion/hash": { + "node_modules/@emotion/cache/node_modules/@emotion/memoize": { "version": "0.8.0", "license": "MIT" }, + "node_modules/@emotion/hash": { + "version": "0.9.0", + "license": "MIT" + }, "node_modules/@emotion/is-prop-valid": { "version": "0.8.8", "license": "MIT", @@ -2181,15 +2434,16 @@ "license": "MIT" }, "node_modules/@emotion/react": { - "version": "11.9.3", + "version": "11.10.4", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.13.10", - "@emotion/babel-plugin": "^11.7.1", - "@emotion/cache": "^11.9.3", - "@emotion/serialize": "^1.0.4", - "@emotion/utils": "^1.1.0", - "@emotion/weak-memoize": "^0.2.5", + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.0", + "@emotion/cache": "^11.10.0", + "@emotion/serialize": "^1.1.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", "hoist-non-react-statics": "^3.3.1" }, "peerDependencies": { @@ -2206,18 +2460,22 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.0.4", + "version": "1.1.0", "license": "MIT", "dependencies": { - "@emotion/hash": "^0.8.0", - "@emotion/memoize": "^0.7.4", - "@emotion/unitless": "^0.7.5", - "@emotion/utils": "^1.0.0", + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/unitless": "^0.8.0", + "@emotion/utils": "^1.2.0", "csstype": "^3.0.2" } }, + "node_modules/@emotion/serialize/node_modules/@emotion/memoize": { + "version": "0.8.0", + "license": "MIT" + }, "node_modules/@emotion/sheet": { - "version": "1.1.1", + "version": "1.2.0", "license": "MIT" }, "node_modules/@emotion/styled": { @@ -2252,19 +2510,27 @@ } }, "node_modules/@emotion/unitless": { - "version": "0.7.5", + "version": "0.8.0", "license": "MIT" }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.0", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/@emotion/utils": { - "version": "1.1.0", + "version": "1.2.0", "license": "MIT" }, "node_modules/@emotion/weak-memoize": { - "version": "0.2.5", + "version": "0.3.0", "license": "MIT" }, "node_modules/@eslint/eslintrc": { "version": "1.1.0", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", @@ -2283,6 +2549,7 @@ }, "node_modules/@eslint/eslintrc/node_modules/ignore": { "version": "4.0.6", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -2348,6 +2615,18 @@ "react-dom": "^17.0.2" } }, + "node_modules/@fidesui/react-button": { + "version": "0.0.6", + "license": "MIT", + "dependencies": { + "@chakra-ui/button": "^1.5.3" + }, + "peerDependencies": { + "@chakra-ui/system": "^1.10.3", + "react": "^17.0.2", + "react-dom": "^17.0.2" + } + }, "node_modules/@fidesui/react/node_modules/@chakra-ui/accordion": { "version": "1.4.6", "license": "MIT", @@ -2451,18 +2730,6 @@ "react": ">=16.8.6" } }, - "node_modules/@fidesui/react/node_modules/@chakra-ui/color-mode": { - "version": "1.4.3", - "license": "MIT", - "dependencies": { - "@chakra-ui/hooks": "1.8.2", - "@chakra-ui/react-env": "1.1.4", - "@chakra-ui/utils": "1.10.2" - }, - "peerDependencies": { - "react": ">=16.8.6" - } - }, "node_modules/@fidesui/react/node_modules/@chakra-ui/control-box": { "version": "1.1.4", "license": "MIT", @@ -2866,14 +3133,6 @@ "react": ">=16.8.6" } }, - "node_modules/@fidesui/react/node_modules/@chakra-ui/styled-system": { - "version": "1.17.2", - "license": "MIT", - "dependencies": { - "@chakra-ui/utils": "1.10.2", - "csstype": "^3.0.9" - } - }, "node_modules/@fidesui/react/node_modules/@chakra-ui/switch": { "version": "1.3.5", "license": "MIT", @@ -3045,18 +3304,6 @@ "react": ">=16.8.6" } }, - "node_modules/@fidesui/react/node_modules/@fidesui/react-button": { - "version": "0.0.6", - "license": "MIT", - "dependencies": { - "@chakra-ui/button": "^1.5.3" - }, - "peerDependencies": { - "@chakra-ui/system": "^1.10.3", - "react": "^17.0.2", - "react-dom": "^17.0.2" - } - }, "node_modules/@fidesui/react/node_modules/@fidesui/react-provider": { "version": "0.0.10", "license": "MIT", @@ -3089,6 +3336,7 @@ }, "node_modules/@humanwhocodes/config-array": { "version": "0.9.3", + "dev": true, "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -3101,6 +3349,7 @@ }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/@istanbuljs/load-nyc-config": { @@ -3366,19 +3615,6 @@ } } }, - "node_modules/@jest/reporters/node_modules/jest-worker": { - "version": "27.5.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, "node_modules/@jest/reporters/node_modules/source-map": { "version": "0.6.1", "dev": true, @@ -3387,20 +3623,6 @@ "node": ">=0.10.0" } }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "8.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/@jest/source-map": { "version": "27.5.1", "dev": true, @@ -3498,6 +3720,19 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.0.5", "license": "MIT", @@ -3505,12 +3740,29 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.11", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.4", + "version": "0.3.15", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -3519,14 +3771,35 @@ }, "node_modules/@jsdevtools/ono": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/@monaco-editor/loader": { + "version": "1.3.2", + "license": "MIT", + "dependencies": { + "state-local": "^1.0.6" + }, + "peerDependencies": { + "monaco-editor": ">= 0.21.0 < 1" + } + }, + "node_modules/@monaco-editor/react": { + "version": "4.4.6", + "license": "MIT", + "dependencies": { + "@monaco-editor/loader": "^1.3.2", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "monaco-editor": ">= 0.25.0 < 1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } }, "node_modules/@mswjs/cookies": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-0.2.2.tgz", - "integrity": "sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==", + "version": "0.2.1", + "license": "MIT", "dependencies": { "@types/set-cookie-parser": "^2.4.0", "set-cookie-parser": "^2.4.6" @@ -3536,9 +3809,8 @@ } }, "node_modules/@mswjs/interceptors": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.16.6.tgz", - "integrity": "sha512-7ax1sRx5s4ZWl0KvVhhcPOUoPbCCkVh8M8hYaqOyvoAQOiqLVzy+Z6Mh2ywPhYw4zudr5Mo/E8UT/zJBO/Wxrw==", + "version": "0.16.4", + "license": "MIT", "dependencies": { "@open-draft/until": "^1.0.3", "@xmldom/xmldom": "^0.7.5", @@ -3638,15 +3910,7 @@ }, "node_modules/@open-draft/until": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz", - "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==" - }, - "node_modules/@panva/hkdf": { - "version": "1.0.1", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } + "license": "MIT" }, "node_modules/@polka/url": { "version": "1.0.0-next.21", @@ -3910,6 +4174,29 @@ "version": "0.4.1", "license": "MIT" }, + "node_modules/@types/eslint": { + "version": "8.4.6", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.51", + "license": "MIT", + "peer": true + }, "node_modules/@types/graceful-fs": { "version": "4.1.5", "dev": true, @@ -3991,13 +4278,11 @@ }, "node_modules/@types/js-yaml": { "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz", - "integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.9", - "dev": true, "license": "MIT" }, "node_modules/@types/json5": { @@ -4010,7 +4295,7 @@ "license": "MIT" }, "node_modules/@types/lodash.debounce": { - "version": "4.0.6", + "version": "4.0.7", "dev": true, "license": "MIT", "dependencies": { @@ -4059,7 +4344,7 @@ } }, "node_modules/@types/react-redux": { - "version": "7.1.23", + "version": "7.1.24", "license": "MIT", "dependencies": { "@types/hoist-non-react-statics": "^3.3.0", @@ -4069,7 +4354,7 @@ } }, "node_modules/@types/react-transition-group": { - "version": "4.4.4", + "version": "4.4.5", "license": "MIT", "dependencies": { "@types/react": "*" @@ -4081,8 +4366,7 @@ }, "node_modules/@types/set-cookie-parser": { "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz", - "integrity": "sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==", + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -4360,21 +4644,161 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "license": "MIT", + "peer": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, "node_modules/@xmldom/xmldom": { "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.5.tgz", - "integrity": "sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==", + "license": "MIT", "engines": { "node": ">=10.0.0" } }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "license": "Apache-2.0", + "peer": true + }, "node_modules/abab": { "version": "2.0.5", "dev": true, "license": "BSD-3-Clause" }, "node_modules/acorn": { - "version": "8.7.0", + "version": "8.8.0", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -4411,8 +4835,17 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "license": "MIT", + "peer": true, + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", + "dev": true, "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -4463,6 +4896,13 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "dev": true, @@ -4737,6 +5177,23 @@ "@babel/core": "^7.8.0" } }, + "node_modules/babel-loader": { + "version": "8.2.5", + "license": "MIT", + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", "dev": true, @@ -4767,12 +5224,23 @@ } }, "node_modules/babel-plugin-macros": { - "version": "2.8.0", + "version": "3.1.0", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.7.2", - "cosmiconfig": "^6.0.0", - "resolve": "^1.12.0" + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-transform-remove-imports": { + "version": "1.7.0", + "license": "MIT", + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, "node_modules/babel-preset-current-node-syntax": { @@ -4814,6 +5282,7 @@ }, "node_modules/balanced-match": { "version": "1.0.2", + "dev": true, "license": "MIT" }, "node_modules/base64-js": { @@ -4842,6 +5311,13 @@ "tweetnacl": "^0.14.3" } }, + "node_modules/big.js": { + "version": "5.2.2", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "license": "MIT", @@ -4870,6 +5346,7 @@ }, "node_modules/brace-expansion": { "version": "1.1.11", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -4952,7 +5429,6 @@ }, "node_modules/buffer-from": { "version": "1.1.2", - "dev": true, "license": "MIT" }, "node_modules/cachedir": { @@ -4977,9 +5453,8 @@ }, "node_modules/call-me-maybe": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/callsites": { "version": "3.1.0", @@ -4997,12 +5472,18 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001314", - "license": "CC-BY-4.0", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } + "version": "1.0.30001414", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ], + "license": "CC-BY-4.0" }, "node_modules/caseless": { "version": "0.12.0", @@ -5010,7 +5491,7 @@ "license": "Apache-2.0" }, "node_modules/chakra-react-select": { - "version": "3.3.7", + "version": "3.3.8", "license": "MIT", "dependencies": { "@chakra-ui/form-control": "^1.0.0", @@ -5093,7 +5574,15 @@ "is-glob": "^4.0.1" }, "engines": { - "node": ">= 6" + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.0" } }, "node_modules/ci-info": { @@ -5246,12 +5735,17 @@ "node": ">=4.0.0" } }, + "node_modules/commondir": { + "version": "1.0.1", + "license": "MIT" + }, "node_modules/compute-scroll-into-view": { "version": "1.0.14", "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", + "dev": true, "license": "MIT" }, "node_modules/confusing-browser-globals": { @@ -5296,17 +5790,17 @@ "license": "MIT" }, "node_modules/cosmiconfig": { - "version": "6.0.0", + "version": "7.0.1", "license": "MIT", "dependencies": { "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", + "import-fresh": "^3.2.1", "parse-json": "^5.0.0", "path-type": "^4.0.0", - "yaml": "^1.7.2" + "yaml": "^1.10.0" }, "engines": { - "node": ">=8" + "node": ">=10" } }, "node_modules/cross-env": { @@ -5328,6 +5822,7 @@ }, "node_modules/cross-spawn": { "version": "7.0.3", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -5394,7 +5889,7 @@ "license": "MIT" }, "node_modules/cypress": { - "version": "10.3.0", + "version": "10.7.0", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -5450,7 +5945,7 @@ } }, "node_modules/cypress/node_modules/@types/node": { - "version": "14.18.21", + "version": "14.18.28", "dev": true, "license": "MIT" }, @@ -5593,7 +6088,7 @@ } }, "node_modules/dayjs": { - "version": "1.11.3", + "version": "1.11.5", "dev": true, "license": "MIT" }, @@ -5636,6 +6131,7 @@ }, "node_modules/deep-is": { "version": "0.1.4", + "dev": true, "license": "MIT" }, "node_modules/deepmerge": { @@ -5783,6 +6279,13 @@ "dev": true, "license": "MIT" }, + "node_modules/emojis-list": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/end-of-stream": { "version": "1.4.4", "dev": true, @@ -5791,6 +6294,18 @@ "once": "^1.4.0" } }, + "node_modules/enhanced-resolve": { + "version": "5.10.0", + "license": "MIT", + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/enquirer": { "version": "2.3.6", "dev": true, @@ -5842,6 +6357,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-module-lexer": { + "version": "0.9.3", + "license": "MIT", + "peer": true + }, "node_modules/es-to-primitive": { "version": "1.2.1", "dev": true, @@ -5953,6 +6473,7 @@ }, "node_modules/eslint": { "version": "8.9.0", + "dev": true, "license": "MIT", "dependencies": { "@eslint/eslintrc": "^1.1.0", @@ -6298,6 +6819,7 @@ }, "node_modules/eslint-plugin-simple-import-sort": { "version": "7.0.0", + "dev": true, "license": "MIT", "peerDependencies": { "eslint": ">=5.0.0" @@ -6305,6 +6827,7 @@ }, "node_modules/eslint-scope": { "version": "7.1.1", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -6316,6 +6839,7 @@ }, "node_modules/eslint-utils": { "version": "3.0.0", + "dev": true, "license": "MIT", "dependencies": { "eslint-visitor-keys": "^2.0.0" @@ -6332,6 +6856,7 @@ }, "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { "version": "2.1.0", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=10" @@ -6339,6 +6864,7 @@ }, "node_modules/eslint-visitor-keys": { "version": "3.3.0", + "dev": true, "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -6346,6 +6872,7 @@ }, "node_modules/eslint/node_modules/doctrine": { "version": "3.0.0", + "dev": true, "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" @@ -6356,6 +6883,7 @@ }, "node_modules/espree": { "version": "9.3.1", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.7.0", @@ -6380,6 +6908,7 @@ }, "node_modules/esquery": { "version": "1.4.0", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" @@ -6407,20 +6936,20 @@ }, "node_modules/esutils": { "version": "2.0.3", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/eventemitter2": { - "version": "6.4.5", + "version": "6.4.8", "dev": true, "license": "MIT" }, "node_modules/events": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", "engines": { "node": ">=0.8.x" } @@ -6573,6 +7102,7 @@ }, "node_modules/fast-levenshtein": { "version": "2.0.6", + "dev": true, "license": "MIT" }, "node_modules/fastq": { @@ -6621,6 +7151,7 @@ }, "node_modules/file-entry-cache": { "version": "6.0.1", + "dev": true, "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" @@ -6639,6 +7170,21 @@ "node": ">=8" } }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, "node_modules/find-root": { "version": "1.1.0", "license": "MIT" @@ -6656,6 +7202,7 @@ }, "node_modules/flat-cache": { "version": "3.0.4", + "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.1.0", @@ -6667,6 +7214,7 @@ }, "node_modules/flatted": { "version": "3.2.5", + "dev": true, "license": "ISC" }, "node_modules/focus-lock": { @@ -6798,6 +7346,7 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", + "dev": true, "license": "ISC" }, "node_modules/fsevents": { @@ -6817,6 +7366,7 @@ }, "node_modules/functional-red-black-tree": { "version": "1.0.1", + "dev": true, "license": "MIT" }, "node_modules/gensync": { @@ -6905,6 +7455,7 @@ }, "node_modules/glob": { "version": "7.2.0", + "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -6923,6 +7474,7 @@ }, "node_modules/glob-parent": { "version": "6.0.2", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -6931,6 +7483,11 @@ "node": ">=10.13.0" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "license": "BSD-2-Clause", + "peer": true + }, "node_modules/global-dirs": { "version": "3.0.0", "dev": true, @@ -6947,6 +7504,7 @@ }, "node_modules/globals": { "version": "13.12.1", + "dev": true, "license": "MIT", "dependencies": { "type-fest": "^0.20.2" @@ -6979,13 +7537,11 @@ }, "node_modules/graceful-fs": { "version": "4.2.9", - "dev": true, "license": "ISC" }, "node_modules/graphql": { "version": "16.5.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.5.0.tgz", - "integrity": "sha512-qbHgh8Ix+j/qY+a/ZcJnFQ+j8ezakqPiHwPiZhV/3PgGlgf96QMBB5/f2rkiC9sgLoy/xvT6TSiaf2nTHJh5iA==", + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -7006,9 +7562,8 @@ }, "node_modules/handlebars": { "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.0", @@ -7027,9 +7582,8 @@ }, "node_modules/handlebars/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -7090,9 +7644,8 @@ } }, "node_modules/headers-polyfill": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.0.9.tgz", - "integrity": "sha512-FFIXpxbA9HZJXofXqS4IBRa7Z8F1Y+/DwxHSEOOTswZxym8Kz+f6DNhrtnCRcjWcTN7LjjbE5stz0UnoUPNprQ==" + "version": "3.0.7", + "license": "MIT" }, "node_modules/hey-listen": { "version": "1.0.8", @@ -7168,7 +7721,7 @@ } }, "node_modules/i18n-iso-countries": { - "version": "7.4.0", + "version": "7.5.0", "license": "MIT", "dependencies": { "diacritics": "1.3.0" @@ -7218,6 +7771,7 @@ }, "node_modules/ignore": { "version": "5.2.0", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -7266,6 +7820,7 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -7281,6 +7836,7 @@ }, "node_modules/inflight": { "version": "1.0.6", + "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -7495,8 +8051,7 @@ }, "node_modules/is-node-process": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.0.1.tgz", - "integrity": "sha512-5IcdXuf++TTNt3oGl9EBdkvndXA8gmc4bz/Y+mdEpWh3Mcn/+kOw6hI7LD5CocqJWMzeb0I0ClndRVNdEPuJXQ==" + "license": "MIT" }, "node_modules/is-number": { "version": "7.0.0", @@ -7622,6 +8177,7 @@ }, "node_modules/isexe": { "version": "2.0.0", + "dev": true, "license": "ISC" }, "node_modules/isstream": { @@ -8069,33 +8625,6 @@ "fsevents": "^2.3.2" } }, - "node_modules/jest-haste-map/node_modules/jest-worker": { - "version": "27.5.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-haste-map/node_modules/supports-color": { - "version": "8.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/jest-jasmine2": { "version": "27.5.1", "dev": true, @@ -8384,33 +8913,6 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-runner/node_modules/jest-worker": { - "version": "27.5.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-runner/node_modules/supports-color": { - "version": "8.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/jest-runtime": { "version": "27.5.1", "dev": true, @@ -8627,11 +9129,29 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jose": { - "version": "4.5.0", + "node_modules/jest-worker": { + "version": "27.5.1", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, "funding": { - "url": "https://github.com/sponsors/panva" + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/js-levenshtein": { @@ -8726,9 +9246,8 @@ }, "node_modules/json-schema-ref-parser": { "version": "9.0.9", - "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", - "integrity": "sha512-qcP2lmGy+JUoQJ4DOQeLaZDqH9qSkeGCK3suKWxJXS82dg728Mn3j97azDMaOUmJAN4uCq91LdPx4K7E8F1a7Q==", "dev": true, + "license": "MIT", "dependencies": { "@apidevtools/json-schema-ref-parser": "9.0.9" }, @@ -8742,6 +9261,7 @@ }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", + "dev": true, "license": "MIT" }, "node_modules/json-stringify-safe": { @@ -8844,6 +9364,7 @@ }, "node_modules/levn": { "version": "0.4.1", + "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", @@ -8883,6 +9404,36 @@ } } }, + "node_modules/loader-runner": { + "version": "4.3.0", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/loader-utils/node_modules/json5": { + "version": "2.2.1", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/locate-path": { "version": "2.0.0", "dev": true, @@ -8909,6 +9460,7 @@ }, "node_modules/lodash.merge": { "version": "4.6.2", + "dev": true, "license": "MIT" }, "node_modules/lodash.mergewith": { @@ -8992,6 +9544,7 @@ }, "node_modules/lru-cache": { "version": "6.0.0", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -9010,7 +9563,6 @@ }, "node_modules/make-dir": { "version": "3.1.0", - "dev": true, "license": "MIT", "dependencies": { "semver": "^6.0.0" @@ -9036,7 +9588,6 @@ }, "node_modules/merge-stream": { "version": "2.0.0", - "dev": true, "license": "MIT" }, "node_modules/merge2": { @@ -9061,7 +9612,6 @@ }, "node_modules/mime-db": { "version": "1.51.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -9069,7 +9619,6 @@ }, "node_modules/mime-types": { "version": "2.1.34", - "dev": true, "license": "MIT", "dependencies": { "mime-db": "1.51.0" @@ -9095,6 +9644,7 @@ }, "node_modules/minimatch": { "version": "3.0.4", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -9107,6 +9657,11 @@ "version": "1.2.6", "license": "MIT" }, + "node_modules/monaco-editor": { + "version": "0.34.0", + "license": "MIT", + "peer": true + }, "node_modules/mrmime": { "version": "1.0.0", "dev": true, @@ -9121,9 +9676,8 @@ }, "node_modules/msw": { "version": "0.43.1", - "resolved": "https://registry.npmjs.org/msw/-/msw-0.43.1.tgz", - "integrity": "sha512-wzhPpL6RsiYkyIUlTCg0aZY0aRZa4Eiubd6MOA5oJVgfuapDmvZrI8OMi4h4e+fpHD+Qsy+4unAjv3wpWia5yw==", "hasInstallScript": true, + "license": "MIT", "dependencies": { "@mswjs/cookies": "^0.2.0", "@mswjs/interceptors": "^0.16.3", @@ -9167,8 +9721,7 @@ }, "node_modules/msw/node_modules/chalk": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -9267,8 +9820,7 @@ }, "node_modules/narrow-minded": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/narrow-minded/-/narrow-minded-1.1.1.tgz", - "integrity": "sha512-X5wagoCtdl7kRn7vGgObAKDp447f5nuEi+kaa47gm5TGwnjTWaddMTI8FG06hdzZTtOCw8mQ+dSGT6MU+bhppg==", + "license": "MIT", "engines": { "node": ">12.0", "npm": ">6.0" @@ -9276,13 +9828,12 @@ }, "node_modules/natural-compare": { "version": "1.4.0", + "dev": true, "license": "MIT" }, "node_modules/neo-async": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "license": "MIT" }, "node_modules/next": { "version": "12.1.0", @@ -9332,44 +9883,25 @@ } } }, - "node_modules/next-auth": { - "version": "4.10.3", - "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.10.3.tgz", - "integrity": "sha512-7zc4aXYc/EEln7Pkcsn21V1IevaTZsMLJwapfbnKA4+JY0+jFzWbt5p/ljugesGIrN4VOZhpZIw50EaFZyghJQ==", - "dependencies": { - "@babel/runtime": "^7.16.3", - "@panva/hkdf": "^1.0.1", - "cookie": "^0.4.1", - "jose": "^4.3.7", - "oauth": "^0.9.15", - "openid-client": "^5.1.0", - "preact": "^10.6.3", - "preact-render-to-string": "^5.1.19", - "uuid": "^8.3.2" - }, - "engines": { - "node": "^12.19.0 || ^14.15.0 || ^16.13.0" - }, - "peerDependencies": { - "nodemailer": "^6.6.5", - "react": "^17.0.2 || ^18", - "react-dom": "^17.0.2 || ^18" - }, - "peerDependenciesMeta": { - "nodemailer": { - "optional": true - } - } - }, "node_modules/next-redux-wrapper": { "version": "7.0.5", - "license": "MIT", + "resolved": "https://registry.npmjs.org/next-redux-wrapper/-/next-redux-wrapper-7.0.5.tgz", + "integrity": "sha512-UFXdAWG5i+GFT8+Hoqpx3GArkPh34fVWF9YoA2VSHlBzsrPtnRd7NWM6FNSYUennpommTpWJ09mu+r/1UxyIkg==", "peerDependencies": { "next": ">=10.0.3", "react": "*", "react-redux": "*" } }, + "node_modules/next-remove-imports": { + "version": "1.0.7", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.14.3", + "babel-loader": "^8.2.2", + "babel-plugin-transform-remove-imports": "^1.5.4" + } + }, "node_modules/node-int64": { "version": "0.4.0", "dev": true, @@ -9402,10 +9934,6 @@ "dev": true, "license": "MIT" }, - "node_modules/oauth": { - "version": "0.9.15", - "license": "MIT" - }, "node_modules/object-assign": { "version": "4.1.1", "license": "MIT", @@ -9413,13 +9941,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-hash": { - "version": "2.2.0", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/object-inspect": { "version": "1.12.0", "dev": true, @@ -9510,15 +10031,9 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/oidc-token-hash": { - "version": "5.0.1", - "license": "MIT", - "engines": { - "node": "^10.13.0 || >=12.0.0" - } - }, "node_modules/once": { "version": "1.4.0", + "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -9539,9 +10054,8 @@ }, "node_modules/openapi-typescript-codegen": { "version": "0.20.1", - "resolved": "https://registry.npmjs.org/openapi-typescript-codegen/-/openapi-typescript-codegen-0.20.1.tgz", - "integrity": "sha512-07Fn/es5a3G696tyqkukmgOr/xH3vGnAp32dQO1mb4mSWmIEgtkMtjm+p7htphGhH0jLX1ruPaGfzU+WkdvIGw==", "dev": true, + "license": "MIT", "dependencies": { "camelcase": "^6.3.0", "commander": "^9.0.0", @@ -9554,9 +10068,8 @@ }, "node_modules/openapi-typescript-codegen/node_modules/camelcase": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -9565,10 +10078,9 @@ } }, "node_modules/openapi-typescript-codegen/node_modules/commander": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz", - "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==", + "version": "9.4.0", "dev": true, + "license": "MIT", "engines": { "node": "^12.20.0 || >=14" } @@ -9581,24 +10093,9 @@ "opener": "bin/opener-bin.js" } }, - "node_modules/openid-client": { - "version": "5.1.3", - "license": "MIT", - "dependencies": { - "jose": "^4.1.4", - "lru-cache": "^6.0.0", - "object-hash": "^2.0.1", - "oidc-token-hash": "^5.0.1" - }, - "engines": { - "node": "^12.19.0 || ^14.15.0 || ^16.13.0" - }, - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/optionator": { "version": "0.9.1", + "dev": true, "license": "MIT", "dependencies": { "deep-is": "^0.1.3", @@ -9647,8 +10144,7 @@ }, "node_modules/outvariant": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.3.0.tgz", - "integrity": "sha512-yeWM9k6UPfG/nzxdaPlJkB2p08hCg4xP6Lx99F+vP8YF7xyZVfTmJjrrNalkmzudD4WFvNLVudQikqUmF8zhVQ==" + "license": "MIT" }, "node_modules/p-limit": { "version": "1.3.0", @@ -9735,6 +10231,7 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -9742,6 +10239,7 @@ }, "node_modules/path-key": { "version": "3.1.1", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9753,8 +10251,7 @@ }, "node_modules/path-to-regexp": { "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", @@ -9805,7 +10302,6 @@ }, "node_modules/pkg-dir": { "version": "4.2.0", - "dev": true, "license": "MIT", "dependencies": { "find-up": "^4.0.0" @@ -9816,7 +10312,6 @@ }, "node_modules/pkg-dir/node_modules/find-up": { "version": "4.1.0", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -9828,7 +10323,6 @@ }, "node_modules/pkg-dir/node_modules/locate-path": { "version": "5.0.0", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -9839,7 +10333,6 @@ }, "node_modules/pkg-dir/node_modules/p-limit": { "version": "2.3.0", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -9853,7 +10346,6 @@ }, "node_modules/pkg-dir/node_modules/p-locate": { "version": "4.1.0", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -9864,7 +10356,6 @@ }, "node_modules/pkg-dir/node_modules/p-try": { "version": "2.2.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -9872,7 +10363,6 @@ }, "node_modules/pkg-dir/node_modules/path-exists": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9911,26 +10401,9 @@ "url": "https://opencollective.com/postcss/" } }, - "node_modules/preact": { - "version": "10.6.6", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/preact" - } - }, - "node_modules/preact-render-to-string": { - "version": "5.1.19", - "license": "MIT", - "dependencies": { - "pretty-format": "^3.8.0" - }, - "peerDependencies": { - "preact": ">=10" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -9938,6 +10411,7 @@ }, "node_modules/prettier": { "version": "2.6.2", + "dev": true, "license": "MIT", "bin": { "prettier": "bin-prettier.js" @@ -9960,10 +10434,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pretty-format": { - "version": "3.8.0", - "license": "MIT" - }, "node_modules/prompts": { "version": "2.4.2", "dev": true, @@ -10042,6 +10512,14 @@ ], "license": "MIT" }, + "node_modules/randombytes": { + "version": "2.1.0", + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/react": { "version": "17.0.2", "license": "MIT", @@ -10079,6 +10557,15 @@ "version": "3.2.0", "license": "MIT" }, + "node_modules/react-feature-flags": { + "version": "1.0.0", + "license": "MIT", + "peerDependencies": { + "prop-types": "^15.5.4", + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, "node_modules/react-focus-lock": { "version": "2.5.2", "license": "MIT", @@ -10185,7 +10672,7 @@ "license": "0BSD" }, "node_modules/react-select": { - "version": "5.3.2", + "version": "5.4.0", "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.0", @@ -10227,7 +10714,7 @@ "license": "0BSD" }, "node_modules/react-transition-group": { - "version": "4.4.2", + "version": "4.4.5", "license": "BSD-3-Clause", "dependencies": { "@babel/runtime": "^7.5.5", @@ -10292,6 +10779,13 @@ "@babel/runtime": "^7.9.2" } }, + "node_modules/redux-persist": { + "version": "6.0.0", + "license": "MIT", + "peerDependencies": { + "redux": ">4.0.0" + } + }, "node_modules/redux-thunk": { "version": "2.4.1", "license": "MIT", @@ -10320,6 +10814,7 @@ }, "node_modules/regexpp": { "version": "3.2.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10423,6 +10918,7 @@ }, "node_modules/rimraf": { "version": "3.0.2", + "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -10497,6 +10993,22 @@ "object-assign": "^4.1.1" } }, + "node_modules/schema-utils": { + "version": "2.7.1", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/semver": { "version": "6.3.0", "license": "ISC", @@ -10504,13 +11016,21 @@ "semver": "bin/semver.js" } }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/set-cookie-parser": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.0.tgz", - "integrity": "sha512-cHMAtSXilfyBePduZEBVPTCftTQWz6ehWJD5YNUg4mqvRosrrjKbo4WS8JkB0/RxonMoohHm7cOGH60mDkRQ9w==" + "version": "2.4.8", + "license": "MIT" }, "node_modules/shebang-command": { "version": "2.0.0", + "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -10521,6 +11041,7 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10608,7 +11129,6 @@ }, "node_modules/source-map-support": { "version": "0.5.21", - "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -10617,7 +11137,6 @@ }, "node_modules/source-map-support/node_modules/source-map": { "version": "0.6.1", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -10671,6 +11190,10 @@ "node": ">=8" } }, + "node_modules/state-local": { + "version": "1.0.7", + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.1", "license": "MIT", @@ -10680,8 +11203,7 @@ }, "node_modules/strict-event-emitter": { "version": "0.2.4", - "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.4.tgz", - "integrity": "sha512-xIqTLS5azUH1djSUsLH9DbP6UnM/nI18vu8d43JigCQEoVsnY+mrlE+qv6kYqs6/1OkMnMIiL6ffedQSZStuoQ==", + "license": "MIT", "dependencies": { "events": "^3.3.0" } @@ -10820,6 +11342,7 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -10895,6 +11418,14 @@ "dev": true, "license": "MIT" }, + "node_modules/tapable": { + "version": "2.2.1", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, "node_modules/terminal-link": { "version": "2.1.1", "dev": true, @@ -10910,6 +11441,78 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/terser": { + "version": "5.15.0", + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.6", + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.1.1", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "license": "MIT", + "peer": true + }, "node_modules/test-exclude": { "version": "6.0.0", "dev": true, @@ -10925,6 +11528,7 @@ }, "node_modules/text-table": { "version": "0.2.0", + "dev": true, "license": "MIT" }, "node_modules/throat": { @@ -11073,6 +11677,7 @@ }, "node_modules/type-check": { "version": "0.4.0", + "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" @@ -11091,6 +11696,7 @@ }, "node_modules/type-fest": { "version": "0.20.2", + "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -11120,10 +11726,9 @@ } }, "node_modules/uglify-js": { - "version": "3.16.2", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.16.2.tgz", - "integrity": "sha512-AaQNokTNgExWrkEYA24BTNMSjyqEXPSfhqoS0AxmHkCJ4U+Dyy5AvbGV/sqxuxficEfGGoX3zWw9R7QpLFfEsg==", + "version": "3.17.0", "dev": true, + "license": "BSD-2-Clause", "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" @@ -11219,6 +11824,7 @@ }, "node_modules/uuid": { "version": "8.3.2", + "dev": true, "license": "MIT", "bin": { "uuid": "dist/bin/uuid" @@ -11226,6 +11832,7 @@ }, "node_modules/v8-compile-cache": { "version": "2.3.0", + "dev": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { @@ -11288,6 +11895,18 @@ "loose-envify": "^1.0.0" } }, + "node_modules/watchpack": { + "version": "2.4.0", + "license": "MIT", + "peer": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "license": "MIT", @@ -11303,6 +11922,52 @@ "node": ">=10.4" } }, + "node_modules/webpack": { + "version": "5.74.0", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, "node_modules/webpack-bundle-analyzer": { "version": "4.3.0", "dev": true, @@ -11325,6 +11990,51 @@ "node": ">= 10.13.0" } }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.1.1", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/whatwg-encoding": { "version": "1.0.5", "dev": true, @@ -11357,6 +12067,7 @@ }, "node_modules/which": { "version": "2.0.2", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -11385,6 +12096,7 @@ }, "node_modules/word-wrap": { "version": "1.2.3", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11392,9 +12104,8 @@ }, "node_modules/wordwrap": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/wrap-ansi": { "version": "7.0.0", @@ -11413,6 +12124,7 @@ }, "node_modules/wrappy": { "version": "1.0.2", + "dev": true, "license": "ISC" }, "node_modules/write-file-atomic": { @@ -11465,6 +12177,7 @@ }, "node_modules/yallist": { "version": "4.0.0", + "dev": true, "license": "ISC" }, "node_modules/yaml": { @@ -11534,8 +12247,6 @@ }, "@apidevtools/json-schema-ref-parser": { "version": "9.0.9", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", - "integrity": "sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==", "dev": true, "requires": { "@jsdevtools/ono": "^7.1.3", @@ -11717,7 +12428,7 @@ } }, "@babel/helper-plugin-utils": { - "version": "7.16.7" + "version": "7.19.0" }, "@babel/helper-simple-access": { "version": "7.16.7", @@ -11855,6 +12566,12 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, "@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", "dev": true, @@ -11912,7 +12629,7 @@ } }, "@babel/runtime": { - "version": "7.16.7", + "version": "7.19.0", "requires": { "regenerator-runtime": "^0.13.4" } @@ -12142,15 +12859,36 @@ } }, "@chakra-ui/color-mode": { - "version": "1.4.1", + "version": "1.4.3", "requires": { - "@chakra-ui/hooks": "1.8.0", - "@chakra-ui/react-env": "1.1.2", - "@chakra-ui/utils": "1.10.0" + "@chakra-ui/hooks": "1.8.2", + "@chakra-ui/react-env": "1.1.4", + "@chakra-ui/utils": "1.10.2" }, "dependencies": { + "@chakra-ui/hooks": { + "version": "1.8.2", + "requires": { + "@chakra-ui/react-utils": "1.2.2", + "@chakra-ui/utils": "1.10.2", + "compute-scroll-into-view": "1.0.14", + "copy-to-clipboard": "3.3.1" + } + }, + "@chakra-ui/react-env": { + "version": "1.1.4", + "requires": { + "@chakra-ui/utils": "1.10.2" + } + }, + "@chakra-ui/react-utils": { + "version": "1.2.2", + "requires": { + "@chakra-ui/utils": "^1.10.2" + } + }, "@chakra-ui/utils": { - "version": "1.10.0", + "version": "1.10.2", "requires": { "@types/lodash.mergewith": "4.6.6", "css-box-model": "1.2.1", @@ -12299,6 +13037,30 @@ } } }, + "@chakra-ui/icons": { + "version": "1.1.7", + "requires": { + "@chakra-ui/icon": "2.0.5", + "@types/react": "^17.0.15" + }, + "dependencies": { + "@chakra-ui/icon": { + "version": "2.0.5", + "requires": { + "@chakra-ui/utils": "1.10.4" + } + }, + "@chakra-ui/utils": { + "version": "1.10.4", + "requires": { + "@types/lodash.mergewith": "4.6.6", + "css-box-model": "1.2.1", + "framesync": "5.3.0", + "lodash.mergewith": "4.6.2" + } + } + } + }, "@chakra-ui/image": { "version": "1.1.3", "requires": { @@ -12556,6 +13318,31 @@ "@chakra-ui/utils": "1.10.0" }, "dependencies": { + "@chakra-ui/color-mode": { + "version": "1.4.1", + "requires": { + "@chakra-ui/hooks": "1.8.0", + "@chakra-ui/react-env": "1.1.2", + "@chakra-ui/utils": "1.10.0" + } + }, + "@chakra-ui/styled-system": { + "version": "1.17.0", + "requires": { + "@chakra-ui/utils": "1.10.0", + "csstype": "^3.0.9" + } + }, + "@chakra-ui/system": { + "version": "1.10.1", + "requires": { + "@chakra-ui/color-mode": "1.4.1", + "@chakra-ui/react-utils": "1.2.1", + "@chakra-ui/styled-system": "1.17.0", + "@chakra-ui/utils": "1.10.0", + "react-fast-compare": "3.2.0" + } + }, "@chakra-ui/utils": { "version": "1.10.0", "requires": { @@ -12640,6 +13427,31 @@ "@chakra-ui/visually-hidden": "1.1.2" }, "dependencies": { + "@chakra-ui/color-mode": { + "version": "1.4.1", + "requires": { + "@chakra-ui/hooks": "1.8.0", + "@chakra-ui/react-env": "1.1.2", + "@chakra-ui/utils": "1.10.0" + } + }, + "@chakra-ui/styled-system": { + "version": "1.17.0", + "requires": { + "@chakra-ui/utils": "1.10.0", + "csstype": "^3.0.9" + } + }, + "@chakra-ui/system": { + "version": "1.10.1", + "requires": { + "@chakra-ui/color-mode": "1.4.1", + "@chakra-ui/react-utils": "1.2.1", + "@chakra-ui/styled-system": "1.17.0", + "@chakra-ui/utils": "1.10.0", + "react-fast-compare": "3.2.0" + } + }, "@chakra-ui/utils": { "version": "1.10.0", "requires": { @@ -12654,11 +13466,28 @@ "@chakra-ui/react-env": { "version": "1.1.2", "requires": { - "@chakra-ui/utils": "1.10.0" + "@chakra-ui/utils": "1.10.0" + }, + "dependencies": { + "@chakra-ui/utils": { + "version": "1.10.0", + "requires": { + "@types/lodash.mergewith": "4.6.6", + "css-box-model": "1.2.1", + "framesync": "5.3.0", + "lodash.mergewith": "4.6.2" + } + } + } + }, + "@chakra-ui/react-utils": { + "version": "1.2.1", + "requires": { + "@chakra-ui/utils": "^1.9.1" }, "dependencies": { "@chakra-ui/utils": { - "version": "1.10.0", + "version": "1.10.4", "requires": { "@types/lodash.mergewith": "4.6.6", "css-box-model": "1.2.1", @@ -12668,12 +13497,6 @@ } } }, - "@chakra-ui/react-utils": { - "version": "1.2.1", - "requires": { - "@chakra-ui/utils": "^1.9.1" - } - }, "@chakra-ui/select": { "version": "1.2.4", "requires": { @@ -12701,6 +13524,31 @@ "@chakra-ui/utils": "1.10.0" }, "dependencies": { + "@chakra-ui/color-mode": { + "version": "1.4.1", + "requires": { + "@chakra-ui/hooks": "1.8.0", + "@chakra-ui/react-env": "1.1.2", + "@chakra-ui/utils": "1.10.0" + } + }, + "@chakra-ui/styled-system": { + "version": "1.17.0", + "requires": { + "@chakra-ui/utils": "1.10.0", + "csstype": "^3.0.9" + } + }, + "@chakra-ui/system": { + "version": "1.10.1", + "requires": { + "@chakra-ui/color-mode": "1.4.1", + "@chakra-ui/react-utils": "1.2.1", + "@chakra-ui/styled-system": "1.17.0", + "@chakra-ui/utils": "1.10.0", + "react-fast-compare": "3.2.0" + } + }, "@chakra-ui/utils": { "version": "1.10.0", "requires": { @@ -12769,14 +13617,14 @@ } }, "@chakra-ui/styled-system": { - "version": "1.17.0", + "version": "1.17.2", "requires": { - "@chakra-ui/utils": "1.10.0", + "@chakra-ui/utils": "1.10.2", "csstype": "^3.0.9" }, "dependencies": { "@chakra-ui/utils": { - "version": "1.10.0", + "version": "1.10.2", "requires": { "@types/lodash.mergewith": "4.6.6", "css-box-model": "1.2.1", @@ -12805,23 +13653,62 @@ } }, "@chakra-ui/system": { - "version": "1.10.1", + "version": "1.12.1", "requires": { - "@chakra-ui/color-mode": "1.4.1", - "@chakra-ui/react-utils": "1.2.1", - "@chakra-ui/styled-system": "1.17.0", - "@chakra-ui/utils": "1.10.0", + "@chakra-ui/color-mode": "1.4.8", + "@chakra-ui/react-utils": "1.2.3", + "@chakra-ui/styled-system": "1.19.0", + "@chakra-ui/utils": "1.10.4", "react-fast-compare": "3.2.0" }, "dependencies": { + "@chakra-ui/color-mode": { + "version": "1.4.8", + "requires": { + "@chakra-ui/hooks": "1.9.1", + "@chakra-ui/react-env": "1.1.6", + "@chakra-ui/utils": "1.10.4" + } + }, + "@chakra-ui/hooks": { + "version": "1.9.1", + "requires": { + "@chakra-ui/react-utils": "1.2.3", + "@chakra-ui/utils": "1.10.4", + "compute-scroll-into-view": "1.0.14", + "copy-to-clipboard": "3.3.1" + } + }, + "@chakra-ui/react-env": { + "version": "1.1.6", + "requires": { + "@chakra-ui/utils": "1.10.4" + } + }, + "@chakra-ui/react-utils": { + "version": "1.2.3", + "requires": { + "@chakra-ui/utils": "^1.10.4" + } + }, + "@chakra-ui/styled-system": { + "version": "1.19.0", + "requires": { + "@chakra-ui/utils": "1.10.4", + "csstype": "3.0.9" + } + }, "@chakra-ui/utils": { - "version": "1.10.0", + "version": "1.10.4", "requires": { "@types/lodash.mergewith": "4.6.6", "css-box-model": "1.2.1", "framesync": "5.3.0", "lodash.mergewith": "4.6.2" } + }, + "csstype": { + "version": "3.0.9" } } }, @@ -12999,7 +13886,7 @@ } }, "@chakra-ui/utils": { - "version": "1.10.4", + "version": "2.0.9", "requires": { "@types/lodash.mergewith": "4.6.6", "css-box-model": "1.2.1", @@ -13093,15 +13980,15 @@ } }, "@emotion/babel-plugin": { - "version": "11.7.2", + "version": "11.10.2", "requires": { - "@babel/helper-module-imports": "^7.12.13", - "@babel/plugin-syntax-jsx": "^7.12.13", - "@babel/runtime": "^7.13.10", - "@emotion/hash": "^0.8.0", - "@emotion/memoize": "^0.7.5", - "@emotion/serialize": "^1.0.2", - "babel-plugin-macros": "^2.6.1", + "@babel/helper-module-imports": "^7.16.7", + "@babel/plugin-syntax-jsx": "^7.17.12", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/serialize": "^1.1.0", + "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", "find-root": "^1.1.0", @@ -13109,11 +13996,8 @@ "stylis": "4.0.13" }, "dependencies": { - "@babel/plugin-syntax-jsx": { - "version": "7.16.7", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } + "@emotion/memoize": { + "version": "0.8.0" }, "convert-source-map": { "version": "1.8.0", @@ -13127,17 +14011,22 @@ } }, "@emotion/cache": { - "version": "11.9.3", + "version": "11.10.3", "requires": { - "@emotion/memoize": "^0.7.4", - "@emotion/sheet": "^1.1.1", - "@emotion/utils": "^1.0.0", - "@emotion/weak-memoize": "^0.2.5", + "@emotion/memoize": "^0.8.0", + "@emotion/sheet": "^1.2.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", "stylis": "4.0.13" + }, + "dependencies": { + "@emotion/memoize": { + "version": "0.8.0" + } } }, "@emotion/hash": { - "version": "0.8.0" + "version": "0.9.0" }, "@emotion/is-prop-valid": { "version": "0.8.8", @@ -13156,29 +14045,35 @@ "version": "0.7.5" }, "@emotion/react": { - "version": "11.9.3", - "requires": { - "@babel/runtime": "^7.13.10", - "@emotion/babel-plugin": "^11.7.1", - "@emotion/cache": "^11.9.3", - "@emotion/serialize": "^1.0.4", - "@emotion/utils": "^1.1.0", - "@emotion/weak-memoize": "^0.2.5", + "version": "11.10.4", + "requires": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.10.0", + "@emotion/cache": "^11.10.0", + "@emotion/serialize": "^1.1.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", "hoist-non-react-statics": "^3.3.1" } }, "@emotion/serialize": { - "version": "1.0.4", + "version": "1.1.0", "requires": { - "@emotion/hash": "^0.8.0", - "@emotion/memoize": "^0.7.4", - "@emotion/unitless": "^0.7.5", - "@emotion/utils": "^1.0.0", + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/unitless": "^0.8.0", + "@emotion/utils": "^1.2.0", "csstype": "^3.0.2" + }, + "dependencies": { + "@emotion/memoize": { + "version": "0.8.0" + } } }, "@emotion/sheet": { - "version": "1.1.1" + "version": "1.2.0" }, "@emotion/styled": { "version": "11.6.0", @@ -13199,16 +14094,21 @@ } }, "@emotion/unitless": { - "version": "0.7.5" + "version": "0.8.0" + }, + "@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.0.0", + "requires": {} }, "@emotion/utils": { - "version": "1.1.0" + "version": "1.2.0" }, "@emotion/weak-memoize": { - "version": "0.2.5" + "version": "0.3.0" }, "@eslint/eslintrc": { "version": "1.1.0", + "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -13222,7 +14122,8 @@ }, "dependencies": { "ignore": { - "version": "4.0.6" + "version": "4.0.6", + "dev": true } } }, @@ -13343,14 +14244,6 @@ "@chakra-ui/utils": "1.10.2" } }, - "@chakra-ui/color-mode": { - "version": "1.4.3", - "requires": { - "@chakra-ui/hooks": "1.8.2", - "@chakra-ui/react-env": "1.1.4", - "@chakra-ui/utils": "1.10.2" - } - }, "@chakra-ui/control-box": { "version": "1.1.4", "requires": { @@ -13599,13 +14492,6 @@ "@chakra-ui/visually-hidden": "1.1.4" } }, - "@chakra-ui/styled-system": { - "version": "1.17.2", - "requires": { - "@chakra-ui/utils": "1.10.2", - "csstype": "^3.0.9" - } - }, "@chakra-ui/switch": { "version": "1.3.5", "requires": { @@ -13712,12 +14598,6 @@ "@chakra-ui/utils": "1.10.2" } }, - "@fidesui/react-button": { - "version": "0.0.6", - "requires": { - "@chakra-ui/button": "^1.5.3" - } - }, "@fidesui/react-provider": { "version": "0.0.10", "requires": { @@ -13734,11 +14614,18 @@ } } }, + "@fidesui/react-button": { + "version": "0.0.6", + "requires": { + "@chakra-ui/button": "^1.5.3" + } + }, "@fontsource/inter": { "version": "4.5.4" }, "@humanwhocodes/config-array": { "version": "0.9.3", + "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -13746,7 +14633,8 @@ } }, "@humanwhocodes/object-schema": { - "version": "1.2.1" + "version": "1.2.1", + "dev": true }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -13929,25 +14817,9 @@ "v8-to-istanbul": "^8.1.0" }, "dependencies": { - "jest-worker": { - "version": "27.5.1", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, "source-map": { "version": "0.6.1", "dev": true - }, - "supports-color": { - "version": "8.1.1", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, @@ -14024,14 +14896,35 @@ "chalk": "^4.0.0" } }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "peer": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "@jridgewell/resolve-uri": { "version": "3.0.5" }, + "@jridgewell/set-array": { + "version": "1.1.2", + "peer": true + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "peer": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "@jridgewell/sourcemap-codec": { "version": "1.4.11" }, "@jridgewell/trace-mapping": { - "version": "0.3.4", + "version": "0.3.15", "requires": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -14039,23 +14932,30 @@ }, "@jsdevtools/ono": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", "dev": true }, + "@monaco-editor/loader": { + "version": "1.3.2", + "requires": { + "state-local": "^1.0.6" + } + }, + "@monaco-editor/react": { + "version": "4.4.6", + "requires": { + "@monaco-editor/loader": "^1.3.2", + "prop-types": "^15.7.2" + } + }, "@mswjs/cookies": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-0.2.2.tgz", - "integrity": "sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==", + "version": "0.2.1", "requires": { "@types/set-cookie-parser": "^2.4.0", "set-cookie-parser": "^2.4.6" } }, "@mswjs/interceptors": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.16.6.tgz", - "integrity": "sha512-7ax1sRx5s4ZWl0KvVhhcPOUoPbCCkVh8M8hYaqOyvoAQOiqLVzy+Z6Mh2ywPhYw4zudr5Mo/E8UT/zJBO/Wxrw==", + "version": "0.16.4", "requires": { "@open-draft/until": "^1.0.3", "@xmldom/xmldom": "^0.7.5", @@ -14121,12 +15021,7 @@ } }, "@open-draft/until": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz", - "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==" - }, - "@panva/hkdf": { - "version": "1.0.1" + "version": "1.0.3" }, "@polka/url": { "version": "1.0.0-next.21", @@ -14305,6 +15200,26 @@ "@types/cookie": { "version": "0.4.1" }, + "@types/eslint": { + "version": "8.4.6", + "peer": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.4", + "peer": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.51", + "peer": true + }, "@types/graceful-fs": { "version": "4.1.5", "dev": true, @@ -14369,13 +15284,10 @@ }, "@types/js-yaml": { "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz", - "integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==", "dev": true }, "@types/json-schema": { - "version": "7.0.9", - "dev": true + "version": "7.0.9" }, "@types/json5": { "version": "0.0.29", @@ -14385,7 +15297,7 @@ "version": "4.14.178" }, "@types/lodash.debounce": { - "version": "4.0.6", + "version": "4.0.7", "dev": true, "requires": { "@types/lodash": "*" @@ -14426,7 +15338,7 @@ } }, "@types/react-redux": { - "version": "7.1.23", + "version": "7.1.24", "requires": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -14435,7 +15347,7 @@ } }, "@types/react-transition-group": { - "version": "4.4.4", + "version": "4.4.5", "requires": { "@types/react": "*" } @@ -14445,8 +15357,6 @@ }, "@types/set-cookie-parser": { "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz", - "integrity": "sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==", "requires": { "@types/node": "*" } @@ -14603,17 +15513,139 @@ "eslint-visitor-keys": "^3.0.0" } }, + "@webassemblyjs/ast": { + "version": "1.11.1", + "peer": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "peer": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "peer": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "peer": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "peer": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "peer": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "peer": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.1", + "peer": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.1", + "peer": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.1", + "peer": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "peer": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "peer": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "peer": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "peer": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.1", + "peer": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, "@xmldom/xmldom": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.5.tgz", - "integrity": "sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==" + "version": "0.7.5" + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "peer": true + }, + "@xtuc/long": { + "version": "4.2.2", + "peer": true }, "abab": { "version": "2.0.5", "dev": true }, "acorn": { - "version": "8.7.0" + "version": "8.8.0" }, "acorn-globals": { "version": "6.0.0", @@ -14633,8 +15665,14 @@ } } }, + "acorn-import-assertions": { + "version": "1.8.0", + "peer": true, + "requires": {} + }, "acorn-jsx": { "version": "5.3.2", + "dev": true, "requires": {} }, "acorn-walk": { @@ -14665,6 +15703,10 @@ "uri-js": "^4.2.2" } }, + "ajv-keywords": { + "version": "3.5.2", + "requires": {} + }, "ansi-colors": { "version": "4.1.3", "dev": true @@ -14820,6 +15862,15 @@ "slash": "^3.0.0" } }, + "babel-loader": { + "version": "8.2.5", + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + } + }, "babel-plugin-istanbul": { "version": "6.1.1", "dev": true, @@ -14842,13 +15893,17 @@ } }, "babel-plugin-macros": { - "version": "2.8.0", + "version": "3.1.0", "requires": { - "@babel/runtime": "^7.7.2", - "cosmiconfig": "^6.0.0", - "resolve": "^1.12.0" + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" } }, + "babel-plugin-transform-remove-imports": { + "version": "1.7.0", + "requires": {} + }, "babel-preset-current-node-syntax": { "version": "1.0.1", "dev": true, @@ -14876,7 +15931,8 @@ } }, "balanced-match": { - "version": "1.0.2" + "version": "1.0.2", + "dev": true }, "base64-js": { "version": "1.5.1" @@ -14888,6 +15944,9 @@ "tweetnacl": "^0.14.3" } }, + "big.js": { + "version": "5.2.2" + }, "binary-extensions": { "version": "2.2.0" }, @@ -14909,6 +15968,7 @@ }, "brace-expansion": { "version": "1.1.11", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -14953,8 +16013,7 @@ "dev": true }, "buffer-from": { - "version": "1.1.2", - "dev": true + "version": "1.1.2" }, "cachedir": { "version": "2.3.0", @@ -14970,8 +16029,6 @@ }, "call-me-maybe": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw==", "dev": true }, "callsites": { @@ -14982,14 +16039,14 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001314" + "version": "1.0.30001414" }, "caseless": { "version": "0.12.0", "dev": true }, "chakra-react-select": { - "version": "3.3.7", + "version": "3.3.8", "requires": { "@chakra-ui/form-control": "^1.0.0", "@chakra-ui/icon": "^2.0.0", @@ -15039,6 +16096,10 @@ } } }, + "chrome-trace-event": { + "version": "1.0.3", + "peer": true + }, "ci-info": { "version": "3.3.0", "dev": true @@ -15126,11 +16187,15 @@ "version": "1.8.2", "dev": true }, + "commondir": { + "version": "1.0.1" + }, "compute-scroll-into-view": { "version": "1.0.14" }, "concat-map": { - "version": "0.0.1" + "version": "0.0.1", + "dev": true }, "confusing-browser-globals": { "version": "1.0.11", @@ -15160,13 +16225,13 @@ "dev": true }, "cosmiconfig": { - "version": "6.0.0", + "version": "7.0.1", "requires": { "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", + "import-fresh": "^3.2.1", "parse-json": "^5.0.0", "path-type": "^4.0.0", - "yaml": "^1.7.2" + "yaml": "^1.10.0" } }, "cross-env": { @@ -15178,6 +16243,7 @@ }, "cross-spawn": { "version": "7.0.3", + "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -15230,7 +16296,7 @@ "version": "3.0.10" }, "cypress": { - "version": "10.3.0", + "version": "10.7.0", "dev": true, "requires": { "@cypress/request": "^2.88.10", @@ -15278,7 +16344,7 @@ }, "dependencies": { "@types/node": { - "version": "14.18.21", + "version": "14.18.28", "dev": true }, "commander": { @@ -15362,7 +16428,7 @@ "requires": {} }, "dayjs": { - "version": "1.11.3", + "version": "1.11.5", "dev": true }, "debounce": { @@ -15387,7 +16453,8 @@ "dev": true }, "deep-is": { - "version": "0.1.4" + "version": "0.1.4", + "dev": true }, "deepmerge": { "version": "2.2.1" @@ -15484,6 +16551,9 @@ "version": "9.2.2", "dev": true }, + "emojis-list": { + "version": "3.0.0" + }, "end-of-stream": { "version": "1.4.4", "dev": true, @@ -15491,6 +16561,14 @@ "once": "^1.4.0" } }, + "enhanced-resolve": { + "version": "5.10.0", + "peer": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, "enquirer": { "version": "2.3.6", "dev": true, @@ -15530,6 +16608,10 @@ "unbox-primitive": "^1.0.1" } }, + "es-module-lexer": { + "version": "0.9.3", + "peer": true + }, "es-to-primitive": { "version": "1.2.1", "dev": true, @@ -15596,6 +16678,7 @@ }, "eslint": { "version": "8.9.0", + "dev": true, "requires": { "@eslint/eslintrc": "^1.1.0", "@humanwhocodes/config-array": "^0.9.2", @@ -15636,6 +16719,7 @@ "dependencies": { "doctrine": { "version": "3.0.0", + "dev": true, "requires": { "esutils": "^2.0.2" } @@ -15847,10 +16931,12 @@ }, "eslint-plugin-simple-import-sort": { "version": "7.0.0", + "dev": true, "requires": {} }, "eslint-scope": { "version": "7.1.1", + "dev": true, "requires": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -15858,20 +16944,24 @@ }, "eslint-utils": { "version": "3.0.0", + "dev": true, "requires": { "eslint-visitor-keys": "^2.0.0" }, "dependencies": { "eslint-visitor-keys": { - "version": "2.1.0" + "version": "2.1.0", + "dev": true } } }, "eslint-visitor-keys": { - "version": "3.3.0" + "version": "3.3.0", + "dev": true }, "espree": { "version": "9.3.1", + "dev": true, "requires": { "acorn": "^8.7.0", "acorn-jsx": "^5.3.1", @@ -15884,6 +16974,7 @@ }, "esquery": { "version": "1.4.0", + "dev": true, "requires": { "estraverse": "^5.1.0" } @@ -15898,16 +16989,15 @@ "version": "5.3.0" }, "esutils": { - "version": "2.0.3" + "version": "2.0.3", + "dev": true }, "eventemitter2": { - "version": "6.4.5", + "version": "6.4.8", "dev": true }, "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + "version": "3.3.0" }, "execa": { "version": "5.1.1", @@ -16007,7 +17097,8 @@ "version": "2.1.0" }, "fast-levenshtein": { - "version": "2.0.6" + "version": "2.0.6", + "dev": true }, "fastq": { "version": "1.13.0", @@ -16043,6 +17134,7 @@ }, "file-entry-cache": { "version": "6.0.1", + "dev": true, "requires": { "flat-cache": "^3.0.4" } @@ -16053,6 +17145,14 @@ "to-regex-range": "^5.0.1" } }, + "find-cache-dir": { + "version": "3.3.2", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, "find-root": { "version": "1.1.0" }, @@ -16065,13 +17165,15 @@ }, "flat-cache": { "version": "3.0.4", + "dev": true, "requires": { "flatted": "^3.1.0", "rimraf": "^3.0.2" } }, "flatted": { - "version": "3.2.5" + "version": "3.2.5", + "dev": true }, "focus-lock": { "version": "0.9.2", @@ -16156,7 +17258,8 @@ } }, "fs.realpath": { - "version": "1.0.0" + "version": "1.0.0", + "dev": true }, "fsevents": { "version": "2.3.2", @@ -16166,7 +17269,8 @@ "version": "1.1.1" }, "functional-red-black-tree": { - "version": "1.0.1" + "version": "1.0.1", + "dev": true }, "gensync": { "version": "1.0.0-beta.2" @@ -16218,6 +17322,7 @@ }, "glob": { "version": "7.2.0", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -16229,10 +17334,15 @@ }, "glob-parent": { "version": "6.0.2", + "dev": true, "requires": { "is-glob": "^4.0.3" } }, + "glob-to-regexp": { + "version": "0.4.1", + "peer": true + }, "global-dirs": { "version": "3.0.0", "dev": true, @@ -16242,6 +17352,7 @@ }, "globals": { "version": "13.12.1", + "dev": true, "requires": { "type-fest": "^0.20.2" } @@ -16259,13 +17370,10 @@ } }, "graceful-fs": { - "version": "4.2.9", - "dev": true + "version": "4.2.9" }, "graphql": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.5.0.tgz", - "integrity": "sha512-qbHgh8Ix+j/qY+a/ZcJnFQ+j8ezakqPiHwPiZhV/3PgGlgf96QMBB5/f2rkiC9sgLoy/xvT6TSiaf2nTHJh5iA==" + "version": "16.5.0" }, "gzip-size": { "version": "6.0.0", @@ -16276,8 +17384,6 @@ }, "handlebars": { "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", "dev": true, "requires": { "minimist": "^1.2.5", @@ -16289,8 +17395,6 @@ "dependencies": { "source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -16324,9 +17428,7 @@ } }, "headers-polyfill": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.0.9.tgz", - "integrity": "sha512-FFIXpxbA9HZJXofXqS4IBRa7Z8F1Y+/DwxHSEOOTswZxym8Kz+f6DNhrtnCRcjWcTN7LjjbE5stz0UnoUPNprQ==" + "version": "3.0.7" }, "hey-listen": { "version": "1.0.8" @@ -16379,7 +17481,7 @@ "dev": true }, "i18n-iso-countries": { - "version": "7.4.0", + "version": "7.5.0", "requires": { "diacritics": "1.3.0" } @@ -16401,7 +17503,8 @@ "version": "1.2.1" }, "ignore": { - "version": "5.2.0" + "version": "5.2.0", + "dev": true }, "immer": { "version": "9.0.15", @@ -16424,7 +17527,8 @@ } }, "imurmurhash": { - "version": "0.1.4" + "version": "0.1.4", + "dev": true }, "indent-string": { "version": "4.0.0", @@ -16432,6 +17536,7 @@ }, "inflight": { "version": "1.0.6", + "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -16558,9 +17663,7 @@ "dev": true }, "is-node-process": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.0.1.tgz", - "integrity": "sha512-5IcdXuf++TTNt3oGl9EBdkvndXA8gmc4bz/Y+mdEpWh3Mcn/+kOw6hI7LD5CocqJWMzeb0I0ClndRVNdEPuJXQ==" + "version": "1.0.1" }, "is-number": { "version": "7.0.0" @@ -16625,7 +17728,8 @@ } }, "isexe": { - "version": "2.0.0" + "version": "2.0.0", + "dev": true }, "isstream": { "version": "0.1.2", @@ -16923,24 +18027,6 @@ "jest-worker": "^27.5.1", "micromatch": "^4.0.4", "walker": "^1.0.7" - }, - "dependencies": { - "jest-worker": { - "version": "27.5.1", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "supports-color": { - "version": "8.1.1", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } } }, "jest-jasmine2": { @@ -17142,24 +18228,6 @@ "jest-worker": "^27.5.1", "source-map-support": "^0.5.6", "throat": "^6.0.1" - }, - "dependencies": { - "jest-worker": { - "version": "27.5.1", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - } - }, - "supports-color": { - "version": "8.1.1", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } } }, "jest-runtime": { @@ -17318,8 +18386,21 @@ "string-length": "^4.0.1" } }, - "jose": { - "version": "4.5.0" + "jest-worker": { + "version": "27.5.1", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "requires": { + "has-flag": "^4.0.0" + } + } + } }, "js-levenshtein": { "version": "1.1.6" @@ -17382,8 +18463,6 @@ }, "json-schema-ref-parser": { "version": "9.0.9", - "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", - "integrity": "sha512-qcP2lmGy+JUoQJ4DOQeLaZDqH9qSkeGCK3suKWxJXS82dg728Mn3j97azDMaOUmJAN4uCq91LdPx4K7E8F1a7Q==", "dev": true, "requires": { "@apidevtools/json-schema-ref-parser": "9.0.9" @@ -17393,7 +18472,8 @@ "version": "0.4.1" }, "json-stable-stringify-without-jsonify": { - "version": "1.0.1" + "version": "1.0.1", + "dev": true }, "json-stringify-safe": { "version": "5.0.1", @@ -17463,6 +18543,7 @@ }, "levn": { "version": "0.4.1", + "dev": true, "requires": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -17485,6 +18566,23 @@ "wrap-ansi": "^7.0.0" } }, + "loader-runner": { + "version": "4.3.0", + "peer": true + }, + "loader-utils": { + "version": "2.0.2", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "dependencies": { + "json5": { + "version": "2.2.1" + } + } + }, "locate-path": { "version": "2.0.0", "dev": true, @@ -17503,7 +18601,8 @@ "version": "4.0.8" }, "lodash.merge": { - "version": "4.6.2" + "version": "4.6.2", + "dev": true }, "lodash.mergewith": { "version": "4.6.2" @@ -17557,6 +18656,7 @@ }, "lru-cache": { "version": "6.0.0", + "dev": true, "requires": { "yallist": "^4.0.0" } @@ -17567,7 +18667,6 @@ }, "make-dir": { "version": "3.1.0", - "dev": true, "requires": { "semver": "^6.0.0" } @@ -17583,8 +18682,7 @@ "version": "5.2.1" }, "merge-stream": { - "version": "2.0.0", - "dev": true + "version": "2.0.0" }, "merge2": { "version": "1.4.1", @@ -17599,12 +18697,10 @@ } }, "mime-db": { - "version": "1.51.0", - "dev": true + "version": "1.51.0" }, "mime-types": { "version": "2.1.34", - "dev": true, "requires": { "mime-db": "1.51.0" } @@ -17618,6 +18714,7 @@ }, "minimatch": { "version": "3.0.4", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -17625,6 +18722,10 @@ "minimist": { "version": "1.2.6" }, + "monaco-editor": { + "version": "0.34.0", + "peer": true + }, "mrmime": { "version": "1.0.0", "dev": true @@ -17634,8 +18735,6 @@ }, "msw": { "version": "0.43.1", - "resolved": "https://registry.npmjs.org/msw/-/msw-0.43.1.tgz", - "integrity": "sha512-wzhPpL6RsiYkyIUlTCg0aZY0aRZa4Eiubd6MOA5oJVgfuapDmvZrI8OMi4h4e+fpHD+Qsy+4unAjv3wpWia5yw==", "requires": { "@mswjs/cookies": "^0.2.0", "@mswjs/interceptors": "^0.16.3", @@ -17661,8 +18760,6 @@ "dependencies": { "chalk": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -17717,18 +18814,14 @@ "version": "3.3.2" }, "narrow-minded": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/narrow-minded/-/narrow-minded-1.1.1.tgz", - "integrity": "sha512-X5wagoCtdl7kRn7vGgObAKDp447f5nuEi+kaa47gm5TGwnjTWaddMTI8FG06hdzZTtOCw8mQ+dSGT6MU+bhppg==" + "version": "1.1.1" }, "natural-compare": { - "version": "1.4.0" + "version": "1.4.0", + "dev": true }, "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "version": "2.6.2" }, "next": { "version": "12.1.0", @@ -17751,26 +18844,20 @@ "use-subscription": "1.5.1" } }, - "next-auth": { - "version": "4.10.3", - "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.10.3.tgz", - "integrity": "sha512-7zc4aXYc/EEln7Pkcsn21V1IevaTZsMLJwapfbnKA4+JY0+jFzWbt5p/ljugesGIrN4VOZhpZIw50EaFZyghJQ==", - "requires": { - "@babel/runtime": "^7.16.3", - "@panva/hkdf": "^1.0.1", - "cookie": "^0.4.1", - "jose": "^4.3.7", - "oauth": "^0.9.15", - "openid-client": "^5.1.0", - "preact": "^10.6.3", - "preact-render-to-string": "^5.1.19", - "uuid": "^8.3.2" - } - }, "next-redux-wrapper": { "version": "7.0.5", + "resolved": "https://registry.npmjs.org/next-redux-wrapper/-/next-redux-wrapper-7.0.5.tgz", + "integrity": "sha512-UFXdAWG5i+GFT8+Hoqpx3GArkPh34fVWF9YoA2VSHlBzsrPtnRd7NWM6FNSYUennpommTpWJ09mu+r/1UxyIkg==", "requires": {} }, + "next-remove-imports": { + "version": "1.0.7", + "requires": { + "@babel/core": "^7.14.3", + "babel-loader": "^8.2.2", + "babel-plugin-transform-remove-imports": "^1.5.4" + } + }, "node-int64": { "version": "0.4.0", "dev": true @@ -17792,15 +18879,9 @@ "version": "2.2.0", "dev": true }, - "oauth": { - "version": "0.9.15" - }, "object-assign": { "version": "4.1.1" }, - "object-hash": { - "version": "2.2.0" - }, "object-inspect": { "version": "1.12.0", "dev": true @@ -17854,11 +18935,9 @@ "es-abstract": "^1.19.1" } }, - "oidc-token-hash": { - "version": "5.0.1" - }, "once": { "version": "1.4.0", + "dev": true, "requires": { "wrappy": "1" } @@ -17871,8 +18950,6 @@ }, "openapi-typescript-codegen": { "version": "0.20.1", - "resolved": "https://registry.npmjs.org/openapi-typescript-codegen/-/openapi-typescript-codegen-0.20.1.tgz", - "integrity": "sha512-07Fn/es5a3G696tyqkukmgOr/xH3vGnAp32dQO1mb4mSWmIEgtkMtjm+p7htphGhH0jLX1ruPaGfzU+WkdvIGw==", "dev": true, "requires": { "camelcase": "^6.3.0", @@ -17883,14 +18960,10 @@ "dependencies": { "camelcase": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true }, "commander": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.3.0.tgz", - "integrity": "sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==", + "version": "9.4.0", "dev": true } } @@ -17899,17 +18972,9 @@ "version": "1.5.2", "dev": true }, - "openid-client": { - "version": "5.1.3", - "requires": { - "jose": "^4.1.4", - "lru-cache": "^6.0.0", - "object-hash": "^2.0.1", - "oidc-token-hash": "^5.0.1" - } - }, "optionator": { "version": "0.9.1", + "dev": true, "requires": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -17941,9 +19006,7 @@ "dev": true }, "outvariant": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.3.0.tgz", - "integrity": "sha512-yeWM9k6UPfG/nzxdaPlJkB2p08hCg4xP6Lx99F+vP8YF7xyZVfTmJjrrNalkmzudD4WFvNLVudQikqUmF8zhVQ==" + "version": "1.3.0" }, "p-limit": { "version": "1.3.0", @@ -17994,18 +19057,18 @@ "dev": true }, "path-is-absolute": { - "version": "1.0.1" + "version": "1.0.1", + "dev": true }, "path-key": { - "version": "3.1.1" + "version": "3.1.1", + "dev": true }, "path-parse": { "version": "1.0.7" }, "path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" + "version": "6.2.1" }, "path-type": { "version": "4.0.0" @@ -18034,14 +19097,12 @@ }, "pkg-dir": { "version": "4.2.0", - "dev": true, "requires": { "find-up": "^4.0.0" }, "dependencies": { "find-up": { "version": "4.1.0", - "dev": true, "requires": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -18049,32 +19110,27 @@ }, "locate-path": { "version": "5.0.0", - "dev": true, "requires": { "p-locate": "^4.1.0" } }, "p-limit": { "version": "2.3.0", - "dev": true, "requires": { "p-try": "^2.0.0" } }, "p-locate": { "version": "4.1.0", - "dev": true, "requires": { "p-limit": "^2.2.0" } }, "p-try": { - "version": "2.2.0", - "dev": true + "version": "2.2.0" }, "path-exists": { - "version": "4.0.0", - "dev": true + "version": "4.0.0" } } }, @@ -18103,28 +19159,18 @@ "source-map-js": "^1.0.1" } }, - "preact": { - "version": "10.6.6" - }, - "preact-render-to-string": { - "version": "5.1.19", - "requires": { - "pretty-format": "^3.8.0" - } - }, "prelude-ls": { - "version": "1.2.1" + "version": "1.2.1", + "dev": true }, "prettier": { - "version": "2.6.2" + "version": "2.6.2", + "dev": true }, "pretty-bytes": { "version": "5.6.0", "dev": true }, - "pretty-format": { - "version": "3.8.0" - }, "prompts": { "version": "2.4.2", "dev": true, @@ -18171,6 +19217,13 @@ "version": "1.2.3", "dev": true }, + "randombytes": { + "version": "2.1.0", + "peer": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, "react": { "version": "17.0.2", "requires": { @@ -18195,6 +19248,10 @@ "react-fast-compare": { "version": "3.2.0" }, + "react-feature-flags": { + "version": "1.0.0", + "requires": {} + }, "react-focus-lock": { "version": "2.5.2", "requires": { @@ -18256,7 +19313,7 @@ } }, "react-select": { - "version": "5.3.2", + "version": "5.4.0", "requires": { "@babel/runtime": "^7.12.0", "@emotion/cache": "^11.4.0", @@ -18281,7 +19338,7 @@ } }, "react-transition-group": { - "version": "4.4.2", + "version": "4.4.5", "requires": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -18323,6 +19380,10 @@ "@babel/runtime": "^7.9.2" } }, + "redux-persist": { + "version": "6.0.0", + "requires": {} + }, "redux-thunk": { "version": "2.4.1", "requires": {} @@ -18339,7 +19400,8 @@ } }, "regexpp": { - "version": "3.2.0" + "version": "3.2.0", + "dev": true }, "request-progress": { "version": "3.0.0", @@ -18399,6 +19461,7 @@ }, "rimraf": { "version": "3.0.2", + "dev": true, "requires": { "glob": "^7.1.3" } @@ -18439,22 +19502,37 @@ "object-assign": "^4.1.1" } }, + "schema-utils": { + "version": "2.7.1", + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, "semver": { "version": "6.3.0" }, + "serialize-javascript": { + "version": "6.0.0", + "peer": true, + "requires": { + "randombytes": "^2.1.0" + } + }, "set-cookie-parser": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.0.tgz", - "integrity": "sha512-cHMAtSXilfyBePduZEBVPTCftTQWz6ehWJD5YNUg4mqvRosrrjKbo4WS8JkB0/RxonMoohHm7cOGH60mDkRQ9w==" + "version": "2.4.8" }, "shebang-command": { "version": "2.0.0", + "dev": true, "requires": { "shebang-regex": "^3.0.0" } }, "shebang-regex": { - "version": "3.0.0" + "version": "3.0.0", + "dev": true }, "side-channel": { "version": "1.0.4", @@ -18511,15 +19589,13 @@ }, "source-map-support": { "version": "0.5.21", - "dev": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" }, "dependencies": { "source-map": { - "version": "0.6.1", - "dev": true + "version": "0.6.1" } } }, @@ -18555,13 +19631,14 @@ } } }, + "state-local": { + "version": "1.0.7" + }, "statuses": { "version": "2.0.1" }, "strict-event-emitter": { "version": "0.2.4", - "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.4.tgz", - "integrity": "sha512-xIqTLS5azUH1djSUsLH9DbP6UnM/nI18vu8d43JigCQEoVsnY+mrlE+qv6kYqs6/1OkMnMIiL6ffedQSZStuoQ==", "requires": { "events": "^3.3.0" } @@ -18650,7 +19727,8 @@ } }, "strip-json-comments": { - "version": "3.1.1" + "version": "3.1.1", + "dev": true }, "style-value-types": { "version": "5.0.0", @@ -18687,6 +19765,10 @@ "version": "3.2.4", "dev": true }, + "tapable": { + "version": "2.2.1", + "peer": true + }, "terminal-link": { "version": "2.1.1", "dev": true, @@ -18695,6 +19777,44 @@ "supports-hyperlinks": "^2.0.0" } }, + "terser": { + "version": "5.15.0", + "peer": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "peer": true + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.6", + "peer": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "dependencies": { + "schema-utils": { + "version": "3.1.1", + "peer": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, "test-exclude": { "version": "6.0.0", "dev": true, @@ -18705,7 +19825,8 @@ } }, "text-table": { - "version": "0.2.0" + "version": "0.2.0", + "dev": true }, "throat": { "version": "6.0.1", @@ -18808,6 +19929,7 @@ }, "type-check": { "version": "0.4.0", + "dev": true, "requires": { "prelude-ls": "^1.2.1" } @@ -18817,7 +19939,8 @@ "dev": true }, "type-fest": { - "version": "0.20.2" + "version": "0.20.2", + "dev": true }, "typedarray-to-buffer": { "version": "3.1.5", @@ -18831,9 +19954,7 @@ "devOptional": true }, "uglify-js": { - "version": "3.16.2", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.16.2.tgz", - "integrity": "sha512-AaQNokTNgExWrkEYA24BTNMSjyqEXPSfhqoS0AxmHkCJ4U+Dyy5AvbGV/sqxuxficEfGGoX3zWw9R7QpLFfEsg==", + "version": "3.17.0", "dev": true, "optional": true }, @@ -18887,10 +20008,12 @@ "version": "1.0.2" }, "uuid": { - "version": "8.3.2" + "version": "8.3.2", + "dev": true }, "v8-compile-cache": { - "version": "2.3.0" + "version": "2.3.0", + "dev": true }, "v8-to-istanbul": { "version": "8.1.1", @@ -18937,6 +20060,14 @@ "loose-envify": "^1.0.0" } }, + "watchpack": { + "version": "2.4.0", + "peer": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, "wcwidth": { "version": "1.0.1", "requires": { @@ -18947,6 +20078,59 @@ "version": "6.1.0", "dev": true }, + "webpack": { + "version": "5.74.0", + "peer": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "peer": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "peer": true + }, + "schema-utils": { + "version": "3.1.1", + "peer": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, "webpack-bundle-analyzer": { "version": "4.3.0", "dev": true, @@ -18962,6 +20146,10 @@ "ws": "^7.3.1" } }, + "webpack-sources": { + "version": "3.2.3", + "peer": true + }, "whatwg-encoding": { "version": "1.0.5", "dev": true, @@ -18987,6 +20175,7 @@ }, "which": { "version": "2.0.2", + "dev": true, "requires": { "isexe": "^2.0.0" } @@ -19003,12 +20192,11 @@ } }, "word-wrap": { - "version": "1.2.3" + "version": "1.2.3", + "dev": true }, "wordwrap": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "dev": true }, "wrap-ansi": { @@ -19020,7 +20208,8 @@ } }, "wrappy": { - "version": "1.0.2" + "version": "1.0.2", + "dev": true }, "write-file-atomic": { "version": "3.0.3", @@ -19049,7 +20238,8 @@ "version": "5.0.8" }, "yallist": { - "version": "4.0.0" + "version": "4.0.0", + "dev": true }, "yaml": { "version": "1.10.2" diff --git a/clients/ctl/admin-ui/package.json b/clients/admin-ui/package.json similarity index 78% rename from clients/ctl/admin-ui/package.json rename to clients/admin-ui/package.json index 9aab7955f3..2ede6c5d7f 100644 --- a/clients/ctl/admin-ui/package.json +++ b/clients/admin-ui/package.json @@ -1,39 +1,43 @@ { - "name": "ctl-admin-ui", + "name": "admin-ui", "private": true, "scripts": { - "dev": "next dev", - "dev-docker": "test -d node_modules || npm install && npm run dev", - "dev:mock": "echo '🚨 Running with mock API'; NEXT_PUBLIC_MOCK_API=true next dev", - "build": "next build", - "start": "next start", - "lint": "eslint . --ext .ts,.tsx", - "test": "jest --watch", - "test:ci": "jest", "analyze": "cross-env ANALYZE=true next build", - "analyze:server": "cross-env BUNDLE_ANALYZE=server next build", "analyze:browser": "cross-env BUNDLE_ANALYZE=browser next build", - "export": "next build && next export", - "copy-export": "mkdir -p ../../../src/fidesctl/ui-build/static/admin/ && rsync -a --delete out/ ../../../src/fidesctl/ui-build/static/admin/", - "prod-export": "npm run export && npm run copy-export", + "analyze:server": "cross-env BUNDLE_ANALYZE=server next build", + "build": "next build", + "chrome:debug": "BROWSER='google chrome' BROWSER_ARGS='--remote-debugging-port=9222' npm run dev", + "copy-export": "mkdir -p ../../src/fides/ui-build/static/admin/ && rsync -a --delete out/ ../../src/fides/ui-build/static/admin/", "cy:open": "cypress open", "cy:run": "cypress run", "cy:start": "next build && NODE_ENV=test next start", - "openapi:generate": "openapi --input http://localhost:8080/openapi.json --output ./src/types/api --exportCore false --exportServices false --indent 2" + "dev": "next dev", + "dev:mock": "echo '🚨 Running with mock API'; NEXT_PUBLIC_MOCK_API=true next dev", + "export": "next build && next export", + "prod-export": "npm run export && npm run copy-export", + "format": "prettier --write src __tests__/", + "format:ci": "prettier --check src __tests__/", + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "eslint . --fix --ext .ts,.tsx", + "openapi:generate": "openapi --input http://localhost:8080/openapi.json --output ./src/types/api --exportCore false --exportServices false --indent 2", + "start": "next start", + "test": "jest --watch", + "test:ci": "jest" }, "dependencies": { + "@chakra-ui/icons": "^1.1.7", "@chakra-ui/react": "^1.8.0", - "@chakra-ui/system": ">=1.0.0", - "@chakra-ui/utils": "^1.10.4", + "@chakra-ui/system": "^1.12.1", + "@chakra-ui/utils": "^2.0.9", "@emotion/react": "^11", "@emotion/styled": "^11", "@fidesui/react": "^0.0.12", "@fontsource/inter": "^4.5.4", + "@monaco-editor/react": "^4.4.5", "@reduxjs/toolkit": "^1.8.0", "chakra-react-select": "^3.3.7", "date-fns": "^2.28.0", "date-fns-tz": "^1.3.1", - "eslint-plugin-simple-import-sort": "^7.0.0", "formik": "^2.2.9", "framer-motion": "^5", "i18n-iso-countries": "^7.4.0", @@ -43,12 +47,13 @@ "msw": "^0.43.0", "narrow-minded": "^1.1.1", "next": "12.1.0", - "next-auth": "^4.10.3", + "next-remove-imports": "^1.0.7", "next-redux-wrapper": "^7.0.5", - "prettier": "^2.6.2", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-feature-flags": "^1.0.0", "react-redux": "^7.2.6", + "redux-persist": "^6.0.0", "whatwg-fetch": "^3.6.2", "yup": "^0.32.11" }, @@ -60,6 +65,7 @@ "@types/lodash.debounce": "^4.0.6", "@types/node": "17.0.10", "@types/react": "17.0.38", + "@types/react-redux": "^7.1.24", "@typescript-eslint/eslint-plugin": "^5.12.0", "@typescript-eslint/parser": "^5.12.0", "babel-jest": "^27.5.1", @@ -76,9 +82,11 @@ "eslint-plugin-no-only-tests": "^3.0.0", "eslint-plugin-react": "^7.28.0", "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-simple-import-sort": "^7.0.0", "identity-obj-proxy": "^3.0.0", "jest": "^27.5.1", "openapi-typescript-codegen": "^0.20.1", + "prettier": "^2.6.2", "typescript": "4.5.5" }, "msw": { diff --git a/clients/ctl/admin-ui/public/favicon.ico b/clients/admin-ui/public/favicon.ico similarity index 100% rename from clients/ctl/admin-ui/public/favicon.ico rename to clients/admin-ui/public/favicon.ico diff --git a/clients/admin-ui/public/images/connector-logos/adobe.svg b/clients/admin-ui/public/images/connector-logos/adobe.svg new file mode 100644 index 0000000000..fadef181c6 --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/adobe.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/clients/admin-ui/public/images/connector-logos/ethyca.svg b/clients/admin-ui/public/images/connector-logos/ethyca.svg new file mode 100644 index 0000000000..32e4384dbe --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/ethyca.svg @@ -0,0 +1,4 @@ + + + + diff --git a/clients/admin-ui/public/images/connector-logos/hubspot.svg b/clients/admin-ui/public/images/connector-logos/hubspot.svg new file mode 100644 index 0000000000..e7afe860e6 --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/hubspot.svg @@ -0,0 +1,4 @@ + + + + diff --git a/clients/admin-ui/public/images/connector-logos/mailchimp.svg b/clients/admin-ui/public/images/connector-logos/mailchimp.svg new file mode 100644 index 0000000000..28edc6cf3e --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/mailchimp.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/clients/admin-ui/public/images/connector-logos/manual_webhook.svg b/clients/admin-ui/public/images/connector-logos/manual_webhook.svg new file mode 100644 index 0000000000..d608862606 --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/manual_webhook.svg @@ -0,0 +1,3 @@ + + + diff --git a/clients/admin-ui/public/images/connector-logos/mariadb.svg b/clients/admin-ui/public/images/connector-logos/mariadb.svg new file mode 100644 index 0000000000..858b783897 --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/mariadb.svg @@ -0,0 +1,4 @@ + + + + diff --git a/clients/admin-ui/public/images/connector-logos/mongodb.svg b/clients/admin-ui/public/images/connector-logos/mongodb.svg new file mode 100644 index 0000000000..e77df3fa46 --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/mongodb.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/clients/admin-ui/public/images/connector-logos/mysql.svg b/clients/admin-ui/public/images/connector-logos/mysql.svg new file mode 100644 index 0000000000..d173889369 --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/mysql.svg @@ -0,0 +1,4 @@ + + + + diff --git a/clients/admin-ui/public/images/connector-logos/outreach.svg b/clients/admin-ui/public/images/connector-logos/outreach.svg new file mode 100644 index 0000000000..769fbb2c5e --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/outreach.svg @@ -0,0 +1,4 @@ + + + + diff --git a/clients/admin-ui/public/images/connector-logos/postgres.svg b/clients/admin-ui/public/images/connector-logos/postgres.svg new file mode 100644 index 0000000000..65080d8212 --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/postgres.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/clients/admin-ui/public/images/connector-logos/redshift.svg b/clients/admin-ui/public/images/connector-logos/redshift.svg new file mode 100644 index 0000000000..1d9993f6e0 --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/redshift.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/clients/admin-ui/public/images/connector-logos/salesforce.svg b/clients/admin-ui/public/images/connector-logos/salesforce.svg new file mode 100644 index 0000000000..d10da329dc --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/salesforce.svg @@ -0,0 +1,4 @@ + + + + diff --git a/clients/admin-ui/public/images/connector-logos/segment.svg b/clients/admin-ui/public/images/connector-logos/segment.svg new file mode 100644 index 0000000000..a84f3677d0 --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/segment.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/clients/admin-ui/public/images/connector-logos/sentry.svg b/clients/admin-ui/public/images/connector-logos/sentry.svg new file mode 100644 index 0000000000..e2e3be20ed --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/sentry.svg @@ -0,0 +1,4 @@ + + + + diff --git a/clients/admin-ui/public/images/connector-logos/snowflake.svg b/clients/admin-ui/public/images/connector-logos/snowflake.svg new file mode 100644 index 0000000000..8b2c3c25c0 --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/snowflake.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/clients/admin-ui/public/images/connector-logos/sqlserver.svg b/clients/admin-ui/public/images/connector-logos/sqlserver.svg new file mode 100644 index 0000000000..a6bea42b26 --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/sqlserver.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/clients/admin-ui/public/images/connector-logos/stripe.svg b/clients/admin-ui/public/images/connector-logos/stripe.svg new file mode 100644 index 0000000000..e41146fffe --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/stripe.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/clients/admin-ui/public/images/connector-logos/zendesk.svg b/clients/admin-ui/public/images/connector-logos/zendesk.svg new file mode 100644 index 0000000000..198243423a --- /dev/null +++ b/clients/admin-ui/public/images/connector-logos/zendesk.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/clients/ctl/admin-ui/public/logo-icon.svg b/clients/admin-ui/public/logo-icon.svg similarity index 100% rename from clients/ctl/admin-ui/public/logo-icon.svg rename to clients/admin-ui/public/logo-icon.svg diff --git a/clients/admin-ui/public/logo.svg b/clients/admin-ui/public/logo.svg new file mode 100644 index 0000000000..9b705e2bf7 --- /dev/null +++ b/clients/admin-ui/public/logo.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/clients/admin-ui/src/app/hooks.ts b/clients/admin-ui/src/app/hooks.ts new file mode 100644 index 0000000000..9951e807dd --- /dev/null +++ b/clients/admin-ui/src/app/hooks.ts @@ -0,0 +1,7 @@ +import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"; + +import type { AppDispatch, RootState } from "./store"; + +export const useAppDispatch: () => AppDispatch = useDispatch; +// eslint-disable-next-line import/prefer-default-export +export const useAppSelector: TypedUseSelectorHook = useSelector; diff --git a/clients/admin-ui/src/app/store.ts b/clients/admin-ui/src/app/store.ts new file mode 100644 index 0000000000..9a19e15355 --- /dev/null +++ b/clients/admin-ui/src/app/store.ts @@ -0,0 +1,206 @@ +import { + AnyAction, + combineReducers, + configureStore, + StateFromReducersMapObject, +} from "@reduxjs/toolkit"; +import { setupListeners } from "@reduxjs/toolkit/query/react"; +import { + connectionTypeApi, + reducer as connectionTypeReducer, +} from "connection-type/index"; +import { + datastoreConnectionApi, + reducer as datastoreConnectionReducer, +} from "datastore-connections/index"; +import { + privacyRequestApi, + reducer as privacyRequestsReducer, +} from "privacy-requests/index"; +import { + FLUSH, + PAUSE, + PERSIST, + persistReducer, + persistStore, + PURGE, + REGISTER, + REHYDRATE, +} from "redux-persist"; +import createWebStorage from "redux-persist/lib/storage/createWebStorage"; +import { + reducer as userManagementReducer, + userApi, +} from "user-management/index"; + +import { STORAGE_ROOT_KEY } from "~/constants"; +import { plusApi } from "~/features/common/plus.slice"; +import { reducer as configWizardReducer } from "~/features/config-wizard/config-wizard.slice"; +import { scannerApi } from "~/features/config-wizard/scanner.slice"; +import { + dataQualifierApi, + reducer as dataQualifierReducer, +} from "~/features/data-qualifier/data-qualifier.slice"; +import { + dataSubjectsApi, + reducer as dataSubjectsReducer, +} from "~/features/data-subjects/data-subject.slice"; +import { + dataUseApi, + reducer as dataUseReducer, +} from "~/features/data-use/data-use.slice"; +import { datasetApi, reducer as datasetReducer } from "~/features/dataset"; +import { + organizationApi, + reducer as organizationReducer, +} from "~/features/organization"; +import { reducer as systemReducer, systemApi } from "~/features/system"; +import { reducer as taxonomyReducer, taxonomyApi } from "~/features/taxonomy"; +import { reducer as userReducer } from "~/features/user"; + +// import { createWrapper } from "next-redux-wrapper"; +import { authApi, AuthState, reducer as authReducer } from "../features/auth"; + +/** + * To prevent the "redux-perist failed to create sync storage. falling back to noop storage" + * console message within Next.js, the following snippet is required. + * {@https://mightycoders.xyz/redux-persist-failed-to-create-sync-storage-falling-back-to-noop-storage} + */ +const createNoopStorage = () => ({ + getItem() { + return Promise.resolve(null); + }, + setItem(_key: any, value: any) { + return Promise.resolve(value); + }, + removeItem() { + return Promise.resolve(); + }, +}); + +const storage = + typeof window !== "undefined" + ? createWebStorage("local") + : createNoopStorage(); + +const reducer = { + [privacyRequestApi.reducerPath]: privacyRequestApi.reducer, + subjectRequests: privacyRequestsReducer, + [userApi.reducerPath]: userApi.reducer, + [authApi.reducerPath]: authApi.reducer, + userManagement: userManagementReducer, + [datastoreConnectionApi.reducerPath]: datastoreConnectionApi.reducer, + datastoreConnections: datastoreConnectionReducer, + auth: authReducer, + [connectionTypeApi.reducerPath]: connectionTypeApi.reducer, + connectionType: connectionTypeReducer, + configWizard: configWizardReducer, + user: userReducer, + dataset: datasetReducer, + taxonomy: taxonomyReducer, + dataQualifier: dataQualifierReducer, + dataSubjects: dataSubjectsReducer, + dataUse: dataUseReducer, + organization: organizationReducer, + system: systemReducer, + [datasetApi.reducerPath]: datasetApi.reducer, + [organizationApi.reducerPath]: organizationApi.reducer, + [scannerApi.reducerPath]: scannerApi.reducer, + [systemApi.reducerPath]: systemApi.reducer, + [taxonomyApi.reducerPath]: taxonomyApi.reducer, + [dataQualifierApi.reducerPath]: dataQualifierApi.reducer, + [dataSubjectsApi.reducerPath]: dataSubjectsApi.reducer, + [dataUseApi.reducerPath]: dataUseApi.reducer, + [plusApi.reducerPath]: plusApi.reducer, + [datastoreConnectionApi.reducerPath]: datastoreConnectionApi.reducer, + [userApi.reducerPath]: userApi.reducer, +}; + +const allReducers = combineReducers(reducer); + +const rootReducer = (state: any, action: AnyAction) => { + let newState = { ...state }; + if (action.type === "auth/logout") { + storage.removeItem(STORAGE_ROOT_KEY); + newState = undefined; + } + return allReducers(newState, action); +}; + +const persistConfig = { + key: "root", + storage, + /* + NOTE: It is also strongly recommended to blacklist any api(s) that you have configured with RTK Query. + If the api slice reducer is not blacklisted, the api cache will be automatically persisted + and restored which could leave you with phantom subscriptions from components that do not exist any more. + (https://redux-toolkit.js.org/usage/usage-guide#use-with-redux-persist) + */ + blacklist: [ + authApi.reducerPath, + connectionTypeApi.reducerPath, + datastoreConnectionApi.reducerPath, + privacyRequestApi.reducerPath, + userApi.reducerPath, + ], +}; + +const persistedReducer = persistReducer(persistConfig, rootReducer); + +export type RootState = StateFromReducersMapObject; + +export const makeStore = (preloadedState?: Partial) => + configureStore({ + reducer: persistedReducer, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + serializableCheck: { + ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], + }, + }).concat( + privacyRequestApi.middleware, + userApi.middleware, + authApi.middleware, + datastoreConnectionApi.middleware, + connectionTypeApi.middleware, + datasetApi.middleware, + organizationApi.middleware, + scannerApi.middleware, + systemApi.middleware, + taxonomyApi.middleware, + dataQualifierApi.middleware, + dataSubjectsApi.middleware, + dataUseApi.middleware, + plusApi.middleware + ), + devTools: true, + preloadedState, + }); + +let storedAuthState: AuthState | undefined; +if (typeof window !== "undefined" && "localStorage" in window) { + const storedAuthStateString = localStorage.getItem(STORAGE_ROOT_KEY); + if (storedAuthStateString) { + try { + storedAuthState = JSON.parse(storedAuthStateString); + } catch (error) { + // TODO: build in formal error logging system + // eslint-disable-next-line no-console + console.error(error); + } + } +} + +const store = makeStore({ + auth: storedAuthState, +}); + +type AppStore = ReturnType; +export type AppDispatch = AppStore["dispatch"]; + +export const persistor = persistStore(store); + +setupListeners(store.dispatch); + +export default store; +// export const wrapper = createWrapper(makeStore); diff --git a/clients/admin-ui/src/constants.ts b/clients/admin-ui/src/constants.ts new file mode 100644 index 0000000000..a19b532f95 --- /dev/null +++ b/clients/admin-ui/src/constants.ts @@ -0,0 +1,117 @@ +import { UserPrivileges } from "user-management/types"; + +export const BASE_API_URN = "/api/v1"; +const API_URL = process.env.NEXT_PUBLIC_FIDESOPS_API + ? process.env.NEXT_PUBLIC_FIDESOPS_API + : ""; +export const BASE_URL = API_URL + BASE_API_URN; + +/** + * Redux-persist storage root key + */ +export const STORAGE_ROOT_KEY = "persist:root"; + +export const USER_PRIVILEGES: UserPrivileges[] = [ + { + privilege: "View subject requests", + scope: "privacy-request:read", + }, + { + privilege: "Approve subject requests", + scope: "privacy-request:review", + }, + { + privilege: "Resume subject requests", + scope: "privacy-request:resume", + }, + { + privilege: "View datastore connections", + scope: "connection:read", + }, + { + privilege: "Create or Update datastore connections", + scope: "connection:create_or_update", + }, + { + privilege: "Instantiate connections to SaaS datastores", + scope: "connection:instantiate", + }, + { + privilege: "Read connection types", + scope: "connection_type:read", + }, + { + privilege: "Delete datastore connections", + scope: "connection:delete", + }, + { + privilege: "View user consent preferences", + scope: "consent:read", + }, + { + privilege: "View Datasets", + scope: "dataset:read", + }, + { + privilege: "Create or Update Datasets", + scope: "dataset:create_or_update", + }, + { + privilege: "Delete Datasets", + scope: "dataset:delete", + }, + { + privilege: "View policies", + scope: "policy:read", + }, + { + privilege: "Create policies", + scope: "policy:create_or_update", + }, + { + privilege: "View users", + scope: "user:read", + }, + { + privilege: "Create users", + scope: "user:create", + }, + { + privilege: "Create roles", + scope: "user-permission:create", + }, + { + privilege: "View roles", + scope: "user-permission:read", + }, + { + privilege: "Upload privacy request data", + scope: "privacy-request:upload_data", + }, + { + privilege: "View privacy request data", + scope: "privacy-request:view_data", + }, + { + privilege: "Create manual webhooks", + scope: "webhook:create_or_update", + }, + { + privilege: "Read manual webhooks", + scope: "webhook:read", + }, + { + privilege: "Delete manual webhooks", + scope: "webhook:delete", + }, +]; + +// API ROUTES +export const INDEX_ROUTE = "/"; +export const LOGIN_ROUTE = "/login"; +export const USER_MANAGEMENT_ROUTE = "/user-management"; +export const CONNECTION_ROUTE = "/connection"; +export const CONNECTION_TYPE_ROUTE = "/connection_type"; + +// UI ROUTES +export const DATASTORE_CONNECTION_ROUTE = "/datastore-connection"; diff --git a/clients/ctl/admin-ui/src/features/YamlForm.tsx b/clients/admin-ui/src/features/YamlForm.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/YamlForm.tsx rename to clients/admin-ui/src/features/YamlForm.tsx diff --git a/clients/admin-ui/src/features/auth/ProtectedRoute.tsx b/clients/admin-ui/src/features/auth/ProtectedRoute.tsx new file mode 100644 index 0000000000..8c6dddc948 --- /dev/null +++ b/clients/admin-ui/src/features/auth/ProtectedRoute.tsx @@ -0,0 +1,40 @@ +import { useRouter } from "next/router"; +import { useSelector } from "react-redux"; + +import { LOGIN_ROUTE } from "../../constants"; +import { selectToken } from "./auth.slice"; + +const useProtectedRoute = (redirectUrl: string) => { + const router = useRouter(); + const token = useSelector(selectToken); + + // TODO: check for token invalidation + if (!token && typeof window !== "undefined") { + router.push(redirectUrl); + return false; + } + + return true; +}; + +interface ProtectedRouteProps { + redirectUrl: string; + authenticatedBlock: JSX.Element; + children: JSX.Element; +} + +const ProtectedRoute = ({ + children, + redirectUrl, + authenticatedBlock, +}: ProtectedRouteProps) => { + const authenticated = useProtectedRoute(redirectUrl); + return authenticated ? children : authenticatedBlock; +}; + +ProtectedRoute.defaultProps = { + authenticatedBlock: null, + redirectUrl: LOGIN_ROUTE, +}; + +export default ProtectedRoute; diff --git a/clients/admin-ui/src/features/auth/__tests__/ProtectedRoute.test.tsx b/clients/admin-ui/src/features/auth/__tests__/ProtectedRoute.test.tsx new file mode 100644 index 0000000000..4799786b52 --- /dev/null +++ b/clients/admin-ui/src/features/auth/__tests__/ProtectedRoute.test.tsx @@ -0,0 +1,110 @@ +import { render, screen } from "../../../../__tests__/test-utils"; +import { LOGIN_ROUTE } from "../../../constants"; +import ProtectedRoute from "../ProtectedRoute"; + +const useRouter = jest.spyOn(require("next/router"), "useRouter"); + +const preloadedLoginState = { + auth: { + user: { + username: "Test", + }, + token: "Valid Token", + }, +}; + +describe("ProtectedRoute", () => { + describe("when user is not logged in", () => { + it("should render provided fallback component before redirecting", () => { + useRouter.mockImplementationOnce(() => ({ + push: () => {}, + })); + render( + Not Authorized}> +
Protected Page
+
, + { + preloadedState: {}, + } + ); + + const unauthorizedMessage = screen.getByText("Not Authorized"); + const protectedContent = screen.queryByText("Protected Page"); + expect(unauthorizedMessage).toBeInTheDocument(); + expect(protectedContent).toBeNull(); + }); + + it(`should default to redirecting to ${LOGIN_ROUTE}`, () => { + const push = jest.fn(); + useRouter.mockImplementationOnce(() => ({ + push, + })); + + render( + +
Protected Page
+
, + { + preloadedState: {}, + } + ); + + expect(push).toHaveBeenCalledWith(LOGIN_ROUTE); + }); + + it("should redirect to specified route", () => { + const push = jest.fn(); + useRouter.mockImplementationOnce(() => ({ + push, + })); + + render( + +
Protected Page
+
, + { + preloadedState: {}, + } + ); + + expect(push).toHaveBeenCalledWith("some/other/page"); + }); + }); + + describe("when the user is logged in", () => { + it("should not redirect", () => { + const push = jest.fn(); + useRouter.mockImplementationOnce(() => ({ + push, + })); + render( + +
Protected Page
+
, + { + preloadedState: preloadedLoginState, + } + ); + expect(push).toBeCalledTimes(0); + }); + + it("should render passed children", () => { + const push = jest.fn(); + useRouter.mockImplementationOnce(() => ({ + push, + })); + + render( + +
Protected Page
+
, + { + preloadedState: preloadedLoginState, + } + ); + + const protectedContent = screen.getByText("Protected Page"); + expect(protectedContent).toBeInTheDocument(); + }); + }); +}); diff --git a/clients/admin-ui/src/features/auth/auth.slice.ts b/clients/admin-ui/src/features/auth/auth.slice.ts new file mode 100644 index 0000000000..3486f0b969 --- /dev/null +++ b/clients/admin-ui/src/features/auth/auth.slice.ts @@ -0,0 +1,112 @@ +import { + createListenerMiddleware, + createSlice, + PayloadAction, +} from "@reduxjs/toolkit"; +import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; +import { addCommonHeaders } from "common/CommonHeaders"; +import { utf8ToB64 } from "common/utils"; +import { User } from "user-management/types"; + +import type { RootState } from "../../app/store"; +import { BASE_URL, STORAGE_ROOT_KEY } from "../../constants"; +import { + LoginRequest, + LoginResponse, + LogoutRequest, + LogoutResponse, +} from "./types"; + +export interface AuthState { + user: User | null; + token: string | null; +} + +const initialState: AuthState = { + token: null, + user: null, +}; + +// Auth slice +export const authSlice = createSlice({ + name: "auth", + initialState, + reducers: { + login( + state, + { payload: { user_data, token_data } }: PayloadAction + ) { + return Object.assign(state, { + user: user_data, + token: token_data.access_token, + }); + }, + logout(state) { + return Object.assign(state, { + user: null, + token: null, + }); + }, + }, +}); + +export const selectAuth = (state: RootState) => state.auth; +export const selectUser = (state: RootState) => selectAuth(state).user; +export const selectToken = (state: RootState) => selectAuth(state).token; + +export const { login, logout } = authSlice.actions; + +export const credentialStorage = createListenerMiddleware(); +credentialStorage.startListening({ + actionCreator: login, + effect: (action, { getState }) => { + if (window && window.localStorage) { + localStorage.setItem( + STORAGE_ROOT_KEY, + JSON.stringify(selectAuth(getState() as RootState)) + ); + } + }, +}); +credentialStorage.startListening({ + actionCreator: logout, + effect: () => { + if (window && window.localStorage) { + localStorage.removeItem(STORAGE_ROOT_KEY); + } + }, +}); + +// Auth API +export const authApi = createApi({ + reducerPath: "authApi", + baseQuery: fetchBaseQuery({ + baseUrl: BASE_URL, + prepareHeaders: (headers, { getState }) => { + const token: string | null = selectToken(getState() as RootState); + addCommonHeaders(headers, token); + return headers; + }, + }), + tagTypes: ["Auth"], + endpoints: (build) => ({ + login: build.mutation({ + query: (credentials) => ({ + url: "login", + method: "POST", + body: { ...credentials, password: utf8ToB64(credentials.password) }, + }), + invalidatesTags: () => ["Auth"], + }), + logout: build.mutation({ + query: () => ({ + url: "logout", + method: "POST", + }), + invalidatesTags: () => ["Auth"], + }), + }), +}); + +export const { useLoginMutation, useLogoutMutation } = authApi; +export const { reducer } = authSlice; diff --git a/clients/admin-ui/src/features/auth/index.ts b/clients/admin-ui/src/features/auth/index.ts new file mode 100644 index 0000000000..900c0f587e --- /dev/null +++ b/clients/admin-ui/src/features/auth/index.ts @@ -0,0 +1 @@ +export * from "./auth.slice"; diff --git a/clients/admin-ui/src/features/auth/types.ts b/clients/admin-ui/src/features/auth/types.ts new file mode 100644 index 0000000000..4490b63ce9 --- /dev/null +++ b/clients/admin-ui/src/features/auth/types.ts @@ -0,0 +1,16 @@ +import { User } from "user-management/types"; + +export interface LoginRequest { + username: string; + password: string; +} + +export interface LoginResponse { + user_data: User; + token_data: { + access_token: string; + }; +} + +export interface LogoutRequest {} +export interface LogoutResponse {} diff --git a/clients/ctl/admin-ui/src/features/common/AccordionTree.tsx b/clients/admin-ui/src/features/common/AccordionTree.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/AccordionTree.tsx rename to clients/admin-ui/src/features/common/AccordionTree.tsx diff --git a/clients/admin-ui/src/features/common/BorderGrid.module.css b/clients/admin-ui/src/features/common/BorderGrid.module.css new file mode 100644 index 0000000000..993e6c26ec --- /dev/null +++ b/clients/admin-ui/src/features/common/BorderGrid.module.css @@ -0,0 +1,15 @@ +.grid-row { + border-top-width: 0.5px; + border-color: var(--chakra-colors-blackAlpha-300); + box-sizing: border-box; +} + +.grid-item { + border-right-width: 0.5px; + border-color: var(--chakra-colors-blackAlpha-300); + box-sizing: border-box; +} + +.grid-item:nth-child(3n) { + border-right-width: 0px; +} diff --git a/clients/ctl/admin-ui/src/features/common/BorderGrid.tsx b/clients/admin-ui/src/features/common/BorderGrid.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/BorderGrid.tsx rename to clients/admin-ui/src/features/common/BorderGrid.tsx diff --git a/clients/ctl/admin-ui/src/features/common/CheckboxTree.tsx b/clients/admin-ui/src/features/common/CheckboxTree.tsx similarity index 99% rename from clients/ctl/admin-ui/src/features/common/CheckboxTree.tsx rename to clients/admin-ui/src/features/common/CheckboxTree.tsx index e6c2ea9400..4bd1b701d5 100644 --- a/clients/ctl/admin-ui/src/features/common/CheckboxTree.tsx +++ b/clients/admin-ui/src/features/common/CheckboxTree.tsx @@ -8,9 +8,9 @@ */ import { Box, Checkbox, IconButton } from "@fidesui/react"; +import { ArrowDownLineIcon, ArrowUpLineIcon } from "common/Icon"; import { Fragment, ReactNode, useEffect, useState } from "react"; -import { ArrowDownLineIcon, ArrowUpLineIcon } from "./Icon"; import { TreeNode } from "./types"; export const getAncestorsAndCurrent = (nodeName: string) => { diff --git a/clients/admin-ui/src/features/common/ClipboardButton.tsx b/clients/admin-ui/src/features/common/ClipboardButton.tsx new file mode 100644 index 0000000000..58e3a4a2db --- /dev/null +++ b/clients/admin-ui/src/features/common/ClipboardButton.tsx @@ -0,0 +1,90 @@ +import { Icon, Tooltip, useClipboard } from "@fidesui/react"; +import React, { useState } from "react"; + +enum TooltipText { + COPY = "Copy", + COPIED = "Copied", +} + +const useClipboardButton = (copyText: string) => { + const { onCopy } = useClipboard(copyText); + + const [highlighted, setHighlighted] = useState(false); + const [tooltipText, setTooltipText] = useState(TooltipText.COPY); + + const handleMouseDown = () => { + setTooltipText(TooltipText.COPIED); + onCopy(); + }; + const handleMouseUp = () => { + setHighlighted(false); + }; + + const handleMouseEnter = () => { + setHighlighted(true); + }; + const handleMouseLeave = () => { + setHighlighted(false); + }; + + return { + tooltipText, + highlighted, + handleMouseDown, + handleMouseUp, + handleMouseEnter, + handleMouseLeave, + setTooltipText, + }; +}; + +type ClipboardButtonProps = { + copyText: string; +}; + +const ClipboardButton = ({ copyText }: ClipboardButtonProps) => { + const { + tooltipText, + highlighted, + handleMouseDown, + handleMouseUp, + handleMouseEnter, + handleMouseLeave, + setTooltipText, + } = useClipboardButton(copyText); + + const iconColor = !highlighted ? "gray.600" : "complimentary.500"; + + return ( + { + setTooltipText(TooltipText.COPY); + }} + onClose={() => { + setTooltipText(TooltipText.COPY); + }} + > + + + + + ); +}; + +export default ClipboardButton; diff --git a/clients/admin-ui/src/features/common/CommonHeaders.ts b/clients/admin-ui/src/features/common/CommonHeaders.ts new file mode 100644 index 0000000000..bad68afe0a --- /dev/null +++ b/clients/admin-ui/src/features/common/CommonHeaders.ts @@ -0,0 +1,11 @@ +/** + * Adds common headers to all api calls to fidesops + */ +export function addCommonHeaders(headers: Headers, token: string | null) { + headers.set("Access-Control-Allow-Origin", "*"); + headers.set("X-Fides-Source", "fidesops-admin-ui"); + if (token) { + headers.set("authorization", `Bearer ${token}`); + } + return headers; +} diff --git a/clients/ctl/admin-ui/src/features/common/ConfirmationModal.tsx b/clients/admin-ui/src/features/common/ConfirmationModal.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/ConfirmationModal.tsx rename to clients/admin-ui/src/features/common/ConfirmationModal.tsx diff --git a/clients/ctl/admin-ui/src/features/common/DataTabs.tsx b/clients/admin-ui/src/features/common/DataTabs.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/DataTabs.tsx rename to clients/admin-ui/src/features/common/DataTabs.tsx diff --git a/clients/admin-ui/src/features/common/DaysLeftTag.tsx b/clients/admin-ui/src/features/common/DaysLeftTag.tsx new file mode 100644 index 0000000000..fd739c74de --- /dev/null +++ b/clients/admin-ui/src/features/common/DaysLeftTag.tsx @@ -0,0 +1,42 @@ +import { Tag } from "@fidesui/react"; +import React from "react"; + +type DaysLeftTagProps = { + daysLeft?: number; + includeText: boolean; +}; + +const DaysLeftTag = ({ daysLeft, includeText }: DaysLeftTagProps) => { + if (!daysLeft) { + return null; + } + + let backgroundColor = ""; + + switch (true) { + case daysLeft >= 10: + backgroundColor = "green.500"; + break; + + case daysLeft < 10 && daysLeft > 4: + backgroundColor = "orange.500"; + break; + + case daysLeft < 5: + backgroundColor = "red.400"; + break; + + default: + break; + } + + const text = includeText ? `${daysLeft} days left` : daysLeft; + + return ( + + {text} + + ); +}; + +export default DaysLeftTag; diff --git a/clients/ctl/admin-ui/src/features/common/DocsLink.tsx b/clients/admin-ui/src/features/common/DocsLink.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/DocsLink.tsx rename to clients/admin-ui/src/features/common/DocsLink.tsx diff --git a/clients/admin-ui/src/features/common/Head.tsx b/clients/admin-ui/src/features/common/Head.tsx new file mode 100644 index 0000000000..7b1985aba8 --- /dev/null +++ b/clients/admin-ui/src/features/common/Head.tsx @@ -0,0 +1,12 @@ +import Head from "next/head"; +import React from "react"; + +const FidesHead = () => ( + + Fides + + + +); + +export default FidesHead; diff --git a/clients/ctl/admin-ui/src/features/common/Header.tsx b/clients/admin-ui/src/features/common/Header.tsx similarity index 63% rename from clients/ctl/admin-ui/src/features/common/Header.tsx rename to clients/admin-ui/src/features/common/Header.tsx index 9679ccb49a..b09e72c53f 100644 --- a/clients/ctl/admin-ui/src/features/common/Header.tsx +++ b/clients/admin-ui/src/features/common/Header.tsx @@ -11,15 +11,29 @@ import { Text, } from "@fidesui/react"; import NextLink from "next/link"; -import { signOut, useSession } from "next-auth/react"; import React from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { INDEX_ROUTE } from "../../constants"; +import { logout, selectUser, useLogoutMutation } from "../auth"; import { QuestionIcon, UserIcon } from "./Icon"; +import Image from "./Image"; -const Header = () => { - const { data: session } = useSession(); - // TODO: what should be displayed if there is no user name? - const username = session?.user?.name ?? ""; +const useHeader = () => { + const { username } = useSelector(selectUser) ?? { username: "" }; + return { username }; +}; + +const Header: React.FC = () => { + const { username } = useHeader(); + const [logoutMutation] = useLogoutMutation(); + const dispatch = useDispatch(); + + const handleLogout = async () => { + logoutMutation({}) + .unwrap() + .then(() => dispatch(logout())); + }; return (
@@ -31,10 +45,10 @@ const Header = () => { justifyContent="space-between" alignItems="center" > - + {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */} - Fidesctl Logo + Fides Logo @@ -43,19 +57,19 @@ const Header = () => { - {username} - - Administrator - + {/* This text should only show if actually an admin */} + {/* + Administrator + */} signOut()} + onClick={handleLogout} > Sign out diff --git a/clients/ctl/admin-ui/src/features/common/HorizontalStepper.tsx b/clients/admin-ui/src/features/common/HorizontalStepper.tsx similarity index 94% rename from clients/ctl/admin-ui/src/features/common/HorizontalStepper.tsx rename to clients/admin-ui/src/features/common/HorizontalStepper.tsx index ccf969d0b4..ac407a441a 100644 --- a/clients/ctl/admin-ui/src/features/common/HorizontalStepper.tsx +++ b/clients/admin-ui/src/features/common/HorizontalStepper.tsx @@ -1,8 +1,7 @@ import { Stack, Text } from "@fidesui/react"; +import { HorizontalLineIcon } from "common/Icon"; import React from "react"; -import { HorizontalLineIcon } from "./Icon/index"; - interface Props { activeStep: number | null; steps: { number: number; name: string }[]; diff --git a/clients/ctl/admin-ui/src/features/common/Icon/AWSLogo.tsx b/clients/admin-ui/src/features/common/Icon/AWSLogo.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/AWSLogo.tsx rename to clients/admin-ui/src/features/common/Icon/AWSLogo.tsx diff --git a/clients/admin-ui/src/features/common/Icon/Add.tsx b/clients/admin-ui/src/features/common/Icon/Add.tsx new file mode 100644 index 0000000000..2b9ad62802 --- /dev/null +++ b/clients/admin-ui/src/features/common/Icon/Add.tsx @@ -0,0 +1,32 @@ +import { createIcon } from "@fidesui/react"; + +export default createIcon({ + displayName: "AddIcon", + viewBox: "0 0 40 40", + path: ( + + + + + + + + + + + ), +}); diff --git a/clients/admin-ui/src/features/common/Icon/ArrowDownLine.tsx b/clients/admin-ui/src/features/common/Icon/ArrowDownLine.tsx new file mode 100644 index 0000000000..acbd0f62c9 --- /dev/null +++ b/clients/admin-ui/src/features/common/Icon/ArrowDownLine.tsx @@ -0,0 +1,11 @@ +import { createIcon } from "@fidesui/react"; + +export default createIcon({ + displayName: "ArrowDownLineIcon", + viewBox: "0 0 24 24", + defaultProps: { + width: "20px", + height: "20px", + }, + d: "M12 13.1719L16.95 8.22192L18.364 9.63592L12 15.9999L5.63599 9.63592L7.04999 8.22192L12 13.1719Z", +}); diff --git a/clients/ctl/admin-ui/src/features/common/Icon/ArrowDownLine.tsx b/clients/admin-ui/src/features/common/Icon/ArrowDownLineCtl.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/ArrowDownLine.tsx rename to clients/admin-ui/src/features/common/Icon/ArrowDownLineCtl.tsx diff --git a/clients/ctl/admin-ui/src/features/common/Icon/ArrowUpLine.tsx b/clients/admin-ui/src/features/common/Icon/ArrowUpLine.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/ArrowUpLine.tsx rename to clients/admin-ui/src/features/common/Icon/ArrowUpLine.tsx diff --git a/clients/admin-ui/src/features/common/Icon/CircleHelp.tsx b/clients/admin-ui/src/features/common/Icon/CircleHelp.tsx new file mode 100644 index 0000000000..90c09e5ad0 --- /dev/null +++ b/clients/admin-ui/src/features/common/Icon/CircleHelp.tsx @@ -0,0 +1,16 @@ +import { createIcon } from "@fidesui/react"; + +export default createIcon({ + displayName: "CircleHelpIcon", + viewBox: "0 0 18 18", + defaultProps: { + width: "18px", + height: "18px", + }, + path: ( + + ), +}); diff --git a/clients/admin-ui/src/features/common/Icon/CloseSolid.tsx b/clients/admin-ui/src/features/common/Icon/CloseSolid.tsx new file mode 100644 index 0000000000..6a4dee4bb4 --- /dev/null +++ b/clients/admin-ui/src/features/common/Icon/CloseSolid.tsx @@ -0,0 +1,13 @@ +import { createIcon } from "@fidesui/react"; + +export default createIcon({ + displayName: "CloseSolidIcon", + defaultProps: { + style: { + width: "17px", + paddingLeft: "2px", + }, + }, + viewBox: "0 0 24 24", + d: "M19.1841 17.5875C19.9562 18.3687 19.9562 19.6343 19.1841 20.4156C18.8012 20.8062 18.2947 21 17.7882 21C17.2818 21 16.7765 20.8047 16.3911 20.414L9.88235 13.8312L3.37421 20.4125C2.98818 20.8062 2.48232 21 1.97647 21C1.47062 21 0.965382 20.8062 0.579044 20.4125C-0.193015 19.6312 -0.193015 18.3656 0.579044 17.5843L7.08904 10.9968L0.579044 4.41248C-0.193015 3.63123 -0.193015 2.3656 0.579044 1.58435C1.3511 0.803101 2.60184 0.803101 3.3739 1.58435L9.88235 8.17497L16.3924 1.58748C17.1644 0.806226 18.4151 0.806226 19.1872 1.58748C19.9593 2.36873 19.9593 3.63435 19.1872 4.4156L12.6772 11.0031L19.1841 17.5875Z", +}); diff --git a/clients/ctl/admin-ui/src/features/common/Icon/CloseSolid.tsx b/clients/admin-ui/src/features/common/Icon/CloseSolidCtl.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/CloseSolid.tsx rename to clients/admin-ui/src/features/common/Icon/CloseSolidCtl.tsx diff --git a/clients/ctl/admin-ui/src/features/common/Icon/DownloadSolid.tsx b/clients/admin-ui/src/features/common/Icon/DownloadSolid.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/DownloadSolid.tsx rename to clients/admin-ui/src/features/common/Icon/DownloadSolid.tsx diff --git a/clients/admin-ui/src/features/common/Icon/ErrorWarning.tsx b/clients/admin-ui/src/features/common/Icon/ErrorWarning.tsx new file mode 100644 index 0000000000..2f489d03d6 --- /dev/null +++ b/clients/admin-ui/src/features/common/Icon/ErrorWarning.tsx @@ -0,0 +1,16 @@ +import { createIcon } from "@fidesui/react"; + +export default createIcon({ + displayName: "ErrorWarningIcon", + viewBox: "0 0 20 20", + defaultProps: { + width: "20px", + height: "20px", + }, + path: ( + + ), +}); diff --git a/clients/ctl/admin-ui/src/features/common/Icon/Eye.tsx b/clients/admin-ui/src/features/common/Icon/Eye.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/Eye.tsx rename to clients/admin-ui/src/features/common/Icon/Eye.tsx diff --git a/clients/ctl/admin-ui/src/features/common/Icon/Gear.tsx b/clients/admin-ui/src/features/common/Icon/Gear.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/Gear.tsx rename to clients/admin-ui/src/features/common/Icon/Gear.tsx diff --git a/clients/admin-ui/src/features/common/Icon/GreenCheckCircle.tsx b/clients/admin-ui/src/features/common/Icon/GreenCheckCircle.tsx new file mode 100644 index 0000000000..3cb414d0b4 --- /dev/null +++ b/clients/admin-ui/src/features/common/Icon/GreenCheckCircle.tsx @@ -0,0 +1,16 @@ +import { createIcon } from "@chakra-ui/react"; + +export default createIcon({ + displayName: "GreenCheckCircleIcon", + viewBox: "0 0 16 16", + defaultProps: { + width: "16px", + height: "16px", + }, + path: ( + + ), +}); diff --git a/clients/ctl/admin-ui/src/features/common/Icon/HorizontalLine.tsx b/clients/admin-ui/src/features/common/Icon/HorizontalLine.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/HorizontalLine.tsx rename to clients/admin-ui/src/features/common/Icon/HorizontalLine.tsx diff --git a/clients/ctl/admin-ui/src/features/common/Icon/ManualSetup.tsx b/clients/admin-ui/src/features/common/Icon/ManualSetup.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/ManualSetup.tsx rename to clients/admin-ui/src/features/common/Icon/ManualSetup.tsx diff --git a/clients/ctl/admin-ui/src/features/common/Icon/More.tsx b/clients/admin-ui/src/features/common/Icon/More.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/More.tsx rename to clients/admin-ui/src/features/common/Icon/More.tsx diff --git a/clients/ctl/admin-ui/src/features/common/Icon/OktaLogo.tsx b/clients/admin-ui/src/features/common/Icon/OktaLogo.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/OktaLogo.tsx rename to clients/admin-ui/src/features/common/Icon/OktaLogo.tsx diff --git a/clients/ctl/admin-ui/src/features/common/Icon/Question.tsx b/clients/admin-ui/src/features/common/Icon/Question.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/Question.tsx rename to clients/admin-ui/src/features/common/Icon/Question.tsx diff --git a/clients/ctl/admin-ui/src/features/common/Icon/SearchLine.tsx b/clients/admin-ui/src/features/common/Icon/SearchLine.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/SearchLine.tsx rename to clients/admin-ui/src/features/common/Icon/SearchLine.tsx diff --git a/clients/admin-ui/src/features/common/Icon/SortArrow.tsx b/clients/admin-ui/src/features/common/Icon/SortArrow.tsx new file mode 100644 index 0000000000..fd87d19745 --- /dev/null +++ b/clients/admin-ui/src/features/common/Icon/SortArrow.tsx @@ -0,0 +1,171 @@ +import { Icon } from "@fidesui/react"; +import React from "react"; + +type SortArrowProps = { + up?: boolean; +}; + +const SortArrow: React.FC = ({ up }) => { + if (up === undefined) { + return ( + + + + + + + ); + } + + if (up) { + return ( + + + + + + + + + + + + + + + + + + + + + + ); + } + + return ( + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default SortArrow; diff --git a/clients/ctl/admin-ui/src/features/common/Icon/StepperCircle.tsx b/clients/admin-ui/src/features/common/Icon/StepperCircle.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/StepperCircle.tsx rename to clients/admin-ui/src/features/common/Icon/StepperCircle.tsx diff --git a/clients/ctl/admin-ui/src/features/common/Icon/StepperCircleCheckmark.tsx b/clients/admin-ui/src/features/common/Icon/StepperCircleCheckmark.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/StepperCircleCheckmark.tsx rename to clients/admin-ui/src/features/common/Icon/StepperCircleCheckmark.tsx diff --git a/clients/admin-ui/src/features/common/Icon/TrashCanSolid.tsx b/clients/admin-ui/src/features/common/Icon/TrashCanSolid.tsx new file mode 100644 index 0000000000..b663e40946 --- /dev/null +++ b/clients/admin-ui/src/features/common/Icon/TrashCanSolid.tsx @@ -0,0 +1,16 @@ +import { createIcon } from "@fidesui/react"; + +export default createIcon({ + displayName: "TrashCanSolidIcon", + viewBox: "0 0 24 24", + defaultProps: { + width: "24px", + height: "24px", + }, + path: ( + + ), +}); diff --git a/clients/ctl/admin-ui/src/features/common/Icon/User.tsx b/clients/admin-ui/src/features/common/Icon/User.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/User.tsx rename to clients/admin-ui/src/features/common/Icon/User.tsx diff --git a/clients/ctl/admin-ui/src/features/common/Icon/VerticalLine.tsx b/clients/admin-ui/src/features/common/Icon/VerticalLine.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Icon/VerticalLine.tsx rename to clients/admin-ui/src/features/common/Icon/VerticalLine.tsx diff --git a/clients/ctl/admin-ui/src/features/common/Icon/index.tsx b/clients/admin-ui/src/features/common/Icon/index.tsx similarity index 74% rename from clients/ctl/admin-ui/src/features/common/Icon/index.tsx rename to clients/admin-ui/src/features/common/Icon/index.tsx index e8d54620a8..9dd9a786ff 100644 --- a/clients/ctl/admin-ui/src/features/common/Icon/index.tsx +++ b/clients/admin-ui/src/features/common/Icon/index.tsx @@ -1,17 +1,23 @@ export { default as AddIcon } from "./Add"; export { default as ArrowDownLineIcon } from "./ArrowDownLine"; +export { default as ArrowDownLineIconCtl } from "./ArrowDownLineCtl"; export { default as ArrowUpLineIcon } from "./ArrowUpLine"; export { default as AWSLogoIcon } from "./AWSLogo"; +export { default as CircleHelpIcon } from "./CircleHelp"; export { default as CloseSolidIcon } from "./CloseSolid"; +export { default as CloseSolidIconCtl } from "./CloseSolidCtl"; export { default as DownloadSolidIcon } from "./DownloadSolid"; +export { default as ErrorWarningIcon } from "./ErrorWarning"; export { default as EyeIcon } from "./Eye"; export { default as GearIcon } from "./Gear"; +export { default as GreenCheckCircleIcon } from "./GreenCheckCircle"; export { default as HorizontalLineIcon } from "./HorizontalLine"; export { default as ManualSetupIcon } from "./ManualSetup"; export { default as MoreIcon } from "./More"; export { default as OktaLogoIcon } from "./OktaLogo"; export { default as QuestionIcon } from "./Question"; export { default as SearchLineIcon } from "./SearchLine"; +export { default as SortArrowIcon } from "./SortArrow"; export { default as StepperCircleIcon } from "./StepperCircle"; export { default as StepperCircleCheckmarkIcon } from "./StepperCircleCheckmark"; export { default as TrashCanSolidIcon } from "./TrashCanSolid"; diff --git a/clients/admin-ui/src/features/common/Image.tsx b/clients/admin-ui/src/features/common/Image.tsx new file mode 100644 index 0000000000..76873231d8 --- /dev/null +++ b/clients/admin-ui/src/features/common/Image.tsx @@ -0,0 +1,11 @@ +// components/Image.js +import NextImage from "next/image"; + +// opt-out of image optimization, no-op +const customLoader = ({ src }: { src: string }) => src; + +const Image: typeof NextImage = (props) => ( + +); + +export default Image; diff --git a/clients/ctl/admin-ui/src/features/common/Layout.tsx b/clients/admin-ui/src/features/common/Layout.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/Layout.tsx rename to clients/admin-ui/src/features/common/Layout.tsx diff --git a/clients/admin-ui/src/features/common/NavBar.tsx b/clients/admin-ui/src/features/common/NavBar.tsx new file mode 100644 index 0000000000..f439417c8f --- /dev/null +++ b/clients/admin-ui/src/features/common/NavBar.tsx @@ -0,0 +1,87 @@ +import { Button, Flex } from "@fidesui/react"; +import NextLink from "next/link"; +import { useRouter } from "next/router"; +import React from "react"; + +import { + DATASTORE_CONNECTION_ROUTE, + INDEX_ROUTE, + USER_MANAGEMENT_ROUTE, +} from "../../constants"; +import Header from "./Header"; +import { ArrowDownLineIcon } from "./Icon"; + +const NavBar = () => { + const router = useRouter(); + + return ( + <> +
+ + + + + + + + + + + + + + + + + + + ); +}; + +export default NavBar; diff --git a/clients/admin-ui/src/features/common/PII.tsx b/clients/admin-ui/src/features/common/PII.tsx new file mode 100644 index 0000000000..f7079fe2d6 --- /dev/null +++ b/clients/admin-ui/src/features/common/PII.tsx @@ -0,0 +1,8 @@ +import { useObscuredPII } from "privacy-requests/helpers"; +import React from "react"; + +const PII: React.FC<{ data: string }> = ({ data }) => ( + <>{useObscuredPII(data)} +); + +export default PII; diff --git a/clients/admin-ui/src/features/common/PIIToggle.tsx b/clients/admin-ui/src/features/common/PIIToggle.tsx new file mode 100644 index 0000000000..c3f98e1ccf --- /dev/null +++ b/clients/admin-ui/src/features/common/PIIToggle.tsx @@ -0,0 +1,13 @@ +import { Switch } from "@fidesui/react"; +import { setRevealPII } from "privacy-requests/privacy-requests.slice"; +import React, { ChangeEvent } from "react"; +import { useDispatch } from "react-redux"; + +const PIIToggle: React.FC = () => { + const dispatch = useDispatch(); + const handleToggle = (event: ChangeEvent) => + dispatch(setRevealPII(event.target.checked)); + return ; +}; + +export default PIIToggle; diff --git a/clients/admin-ui/src/features/common/PaginationFooter.tsx b/clients/admin-ui/src/features/common/PaginationFooter.tsx new file mode 100644 index 0000000000..0ebbc2d82f --- /dev/null +++ b/clients/admin-ui/src/features/common/PaginationFooter.tsx @@ -0,0 +1,54 @@ +import { Button, Flex, Text } from "@fidesui/react"; + +type PaginationFooterProps = { + page: number; + size: number; + total: number; + handleNextPage: () => void; + handlePreviousPage: () => void; +}; + +const PaginationFooter: React.FC = ({ + page, + size, + total, + handleNextPage, + handlePreviousPage, +}) => { + const startingItem = (page - 1) * size + 1; + const endingItem = Math.min(total, page * size); + return ( + + + {total > 0 ? ( + <> + Showing {Number.isNaN(startingItem) ? 0 : startingItem} to{" "} + {Number.isNaN(endingItem) ? 0 : endingItem} of{" "} + {Number.isNaN(total) ? 0 : total} results + + ) : ( + "0 results" + )} + +
+ + +
+
+ ); +}; + +export default PaginationFooter; diff --git a/clients/ctl/admin-ui/src/features/common/QuestionTooltip.tsx b/clients/admin-ui/src/features/common/QuestionTooltip.tsx similarity index 58% rename from clients/ctl/admin-ui/src/features/common/QuestionTooltip.tsx rename to clients/admin-ui/src/features/common/QuestionTooltip.tsx index e0d8842c40..e477f2cac0 100644 --- a/clients/ctl/admin-ui/src/features/common/QuestionTooltip.tsx +++ b/clients/admin-ui/src/features/common/QuestionTooltip.tsx @@ -1,7 +1,6 @@ -import { TooltipProps } from "@chakra-ui/react"; -import { Tooltip } from "@fidesui/react"; - -import { QuestionIcon } from "./Icon"; +import { Tooltip, TooltipProps } from "@chakra-ui/react"; +// import { Tooltip } from "@fidesui/react"; +import { QuestionIcon } from "common/Icon"; const QuestionTooltip = ({ ...props }: Omit) => ( diff --git a/clients/admin-ui/src/features/common/RequestStatusBadge.tsx b/clients/admin-ui/src/features/common/RequestStatusBadge.tsx new file mode 100644 index 0000000000..e175bee606 --- /dev/null +++ b/clients/admin-ui/src/features/common/RequestStatusBadge.tsx @@ -0,0 +1,66 @@ +import { Badge } from "@fidesui/react"; +import { PrivacyRequestStatus } from "privacy-requests/types"; +import { ComponentProps } from "react"; + +export const statusPropMap: { + [key in PrivacyRequestStatus]: ComponentProps; +} = { + approved: { + bg: "yellow.500", + label: "Approved", + }, + complete: { + bg: "green.500", + label: "Completed", + }, + denied: { + bg: "red.500", + label: "Denied", + }, + canceled: { + bg: "red.600", + label: "Canceled", + }, + error: { + bg: "red.800", + label: "Error", + }, + in_processing: { + bg: "orange.500", + label: "In Progress", + }, + paused: { + bg: "gray.400", + label: "Paused", + }, + pending: { + bg: "blue.400", + label: "New", + }, + identity_unverified: { + bg: "red.400", + label: "Unverified", + }, + requires_input: { + bg: "yellow.400", + label: "Requires Input", + }, +}; + +interface RequestBadgeProps { + status: keyof typeof statusPropMap; +} + +const RequestStatusBadge: React.FC = ({ status }) => ( + + {statusPropMap[status].label} + +); + +export default RequestStatusBadge; diff --git a/clients/admin-ui/src/features/common/RequestType.tsx b/clients/admin-ui/src/features/common/RequestType.tsx new file mode 100644 index 0000000000..6f2eab7853 --- /dev/null +++ b/clients/admin-ui/src/features/common/RequestType.tsx @@ -0,0 +1,36 @@ +import { Box, Tag } from "@fidesui/react"; +import { ActionType, Rule } from "privacy-requests/types"; +import React from "react"; + +type RequestTypeProps = { + rules: Rule[]; +}; + +const RequestType = ({ rules }: RequestTypeProps) => { + const actions = Array.from( + new Set( + rules + .filter((d) => Object.values(ActionType).includes(d.action_type)) + .map((d) => + d.action_type === ActionType.ACCESS ? "Download" : "Delete" + ) + ) + ); + const tags = actions.map((action_type) => ( + + {action_type} + + )); + + return {tags}; +}; + +export default RequestType; diff --git a/clients/ctl/admin-ui/src/features/common/SearchBar.tsx b/clients/admin-ui/src/features/common/SearchBar.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/SearchBar.tsx rename to clients/admin-ui/src/features/common/SearchBar.tsx diff --git a/clients/ctl/admin-ui/src/features/common/Stepper.tsx b/clients/admin-ui/src/features/common/Stepper.tsx similarity index 98% rename from clients/ctl/admin-ui/src/features/common/Stepper.tsx rename to clients/admin-ui/src/features/common/Stepper.tsx index 4a10ffa615..0b6850dfeb 100644 --- a/clients/ctl/admin-ui/src/features/common/Stepper.tsx +++ b/clients/admin-ui/src/features/common/Stepper.tsx @@ -1,11 +1,10 @@ import { Box, Stack, Text } from "@fidesui/react"; -import React from "react"; - import { StepperCircleCheckmarkIcon, StepperCircleIcon, VerticalLineIcon, -} from "./Icon"; +} from "common/Icon"; +import React from "react"; interface Props { activeStep: number | null; diff --git a/clients/ctl/admin-ui/src/features/common/constants.tsx b/clients/admin-ui/src/features/common/constants.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/constants.tsx rename to clients/admin-ui/src/features/common/constants.tsx diff --git a/clients/ctl/admin-ui/src/features/common/countries.ts b/clients/admin-ui/src/features/common/countries.ts similarity index 100% rename from clients/ctl/admin-ui/src/features/common/countries.ts rename to clients/admin-ui/src/features/common/countries.ts diff --git a/clients/admin-ui/src/features/common/dropdown/MultiSelectDropdown.tsx b/clients/admin-ui/src/features/common/dropdown/MultiSelectDropdown.tsx new file mode 100644 index 0000000000..2273588642 --- /dev/null +++ b/clients/admin-ui/src/features/common/dropdown/MultiSelectDropdown.tsx @@ -0,0 +1,146 @@ +import { PlacementWithLogical } from "@chakra-ui/react"; +import { + Box, + Button, + HStack, + Menu, + MenuButton, + Text, + Tooltip, +} from "@fidesui/react"; +import React, { useState } from "react"; + +import { ArrowDownLineIcon } from "../Icon"; +import MultiSelectDropdownList from "./MultiSelectDropdownList"; + +type MultiSelectDropdwonProps = { + /** + * Boolean to determine if the dropdown is to be immediately close on a user selection + */ + closeOnSelect?: boolean; + /** + * List of key/value pairs to be rendered as a checkbox list + */ + list: Map; + /** + * Parent callback event handler invoked when list of selection values have changed + */ + onChange: (values: string[]) => void; + /** + * List of key/value pairs which are marked for selection + */ + selectedList: Map; + /** + * Placeholder + */ + label: string; + /** + * Disable showing a tooltip + */ + tooltipDisabled?: boolean; + /** + * Position of the tooltip + */ + tooltipPlacement?: PlacementWithLogical; + /** + * Fixed Width of the textbox within the Menu Button component + */ + width?: string; +}; + +const MultiSelectDropdown: React.FC = ({ + closeOnSelect = false, + list, + onChange, + selectedList, + label, + tooltipDisabled = false, + tooltipPlacement = "auto", + width, +}) => { + const defaultItems = new Map(list); + + // Hooks + const [isOpen, setIsOpen] = useState(false); + + // Listeners + const handleClose = () => { + setIsOpen(false); + }; + const handleOpen = () => { + setIsOpen(true); + }; + const handleSelection = (items: Map) => { + const temp = new Map([...items].filter(([, v]) => v === true)); + onChange([...temp.keys()]); + handleClose(); + }; + + const getMenuButtonText = () => { + if (!tooltipDisabled) { + return selectedList.size > 0 + ? [...selectedList.keys()].sort().join(", ") + : label; + } + return label; + }; + + return ( + + + 0)} + placement={tooltipPlacement} + > + } + size="sm" + variant="outline" + _active={{ + bg: "none", + }} + _hover={{ + bg: "none", + }} + > + {!tooltipDisabled && ( + + {getMenuButtonText()} + + )} + {tooltipDisabled && ( + + {getMenuButtonText()} + {selectedList.size > 0 && ( + {selectedList.size} + )} + + )} + + + {isOpen ? ( + + ) : null} + + + ); +}; + +export default MultiSelectDropdown; diff --git a/clients/admin-ui/src/features/common/dropdown/MultiSelectDropdownList.tsx b/clients/admin-ui/src/features/common/dropdown/MultiSelectDropdownList.tsx new file mode 100644 index 0000000000..e6e8561b85 --- /dev/null +++ b/clients/admin-ui/src/features/common/dropdown/MultiSelectDropdownList.tsx @@ -0,0 +1,111 @@ +import { + Button, + Checkbox, + CheckboxGroup, + Flex, + MenuItem, + MenuList, + Spacer, + Text, +} from "@fidesui/react"; +import React, { useState } from "react"; + +type MultiSelectDropdownListProps = { + /** + * List of default item values + */ + defaultValues?: string[]; + /** + * List of key/value pair items + */ + items: Map; + /** + * Event handler invoked when user item selections are applied + */ + onSelection: (items: Map) => void; +}; + +const MultiSelectDropdownList: React.FC = ({ + defaultValues, + items, + onSelection, +}) => { + const [pendingItems, setPendingItems] = useState(items); + + // Listeners + const handleChange = (values: string[]) => { + // Copy items + const temp = new Map(pendingItems); + + // Uncheck all items + temp.forEach((_value, key) => { + temp.set(key, false); + }); + + // Check the selected items + values.forEach((v) => { + temp.set(v, true); + }); + + setPendingItems(temp); + }; + const handleClear = () => { + setPendingItems(items); + onSelection(new Map()); + }; + const handleDone = () => { + onSelection(pendingItems); + }; + + return ( + + + + + + + {/* MenuItems are not rendered unless Menu is open */} + + {[...items].sort().map(([key]) => ( + + + {key} + + + ))} + + + ); +}; + +export default MultiSelectDropdownList; diff --git a/clients/admin-ui/src/features/common/dropdown/SelectDropdown.tsx b/clients/admin-ui/src/features/common/dropdown/SelectDropdown.tsx new file mode 100644 index 0000000000..cdbebbb9e8 --- /dev/null +++ b/clients/admin-ui/src/features/common/dropdown/SelectDropdown.tsx @@ -0,0 +1,151 @@ +import { + Box, + Button, + Flex, + Menu, + MenuButton, + MenuItem, + MenuList, + Text, + Tooltip, +} from "@fidesui/react"; +import { useState } from "react"; + +import { ArrowDownLineIcon } from "../Icon"; +import { ItemOption } from "./types"; + +type SelectDropdownProps = { + /** + * List of key/value pair items + */ + list: Map; + /** + * Parent callback event handler invoked when selected value has changed + */ + onChange: (value: string | undefined) => void; + /** + * Placeholder + */ + label: string; + /** + * Sort the list items before rendering + */ + enableSorting?: boolean; + /** + * Display the Clear button. Default value is true. + */ + hasClear?: boolean; + /** + * Default value marked for selection + */ + selectedValue?: string; + /** + * Width of an element + */ + width?: string; +}; + +const SelectDropdown: React.FC = ({ + enableSorting = true, + hasClear = true, + label, + list, + onChange, + selectedValue, + width, +}) => { + // Hooks + const [isOpen, setIsOpen] = useState(false); + + // Listeners + const handleClose = () => { + setIsOpen(false); + }; + const handleClear = () => { + onChange(undefined); + handleClose(); + }; + const handleOpen = () => { + setIsOpen(true); + }; + + const selectedText = [...list].find( + ([, option]) => option.value === selectedValue + )?.[0]; + + return ( + + + } + size="sm" + variant="outline" + width={width} + _active={{ + bg: "none", + }} + _hover={{ + bg: "none", + }} + > + {selectedText ?? label} + + {isOpen ? ( + + {hasClear && ( + + + + )} + {/* MenuItems are not rendered unless Menu is open */} + {(enableSorting ? [...list].sort() : [...list]).map( + ([key, option]) => ( + + onChange(option.value)} + paddingTop="10px" + paddingRight="8.5px" + paddingBottom="10px" + paddingLeft="8.5px" + _focus={{ + bg: "gray.100", + }} + > + {key} + + + ) + )} + + ) : null} + + + ); +}; + +export default SelectDropdown; diff --git a/clients/admin-ui/src/features/common/dropdown/types.ts b/clients/admin-ui/src/features/common/dropdown/types.ts new file mode 100644 index 0000000000..1e4b265d8c --- /dev/null +++ b/clients/admin-ui/src/features/common/dropdown/types.ts @@ -0,0 +1,14 @@ +export type ItemOption = { + /** + * Specifies the value to be sent + */ + value: string; + /** + * Specifies that an option should be disabled + */ + isDisabled?: boolean; + /** + * Specifies a toolTip should be dislayed when the user hovers over an option + */ + toolTip?: string; +}; diff --git a/clients/ctl/admin-ui/src/features/common/features.slice.ts b/clients/admin-ui/src/features/common/features.slice.ts similarity index 100% rename from clients/ctl/admin-ui/src/features/common/features.slice.ts rename to clients/admin-ui/src/features/common/features.slice.ts diff --git a/clients/ctl/admin-ui/src/features/common/form/inputs.tsx b/clients/admin-ui/src/features/common/form/inputs.tsx similarity index 100% rename from clients/ctl/admin-ui/src/features/common/form/inputs.tsx rename to clients/admin-ui/src/features/common/form/inputs.tsx diff --git a/clients/ctl/admin-ui/src/features/common/helpers.ts b/clients/admin-ui/src/features/common/helpers.ts similarity index 57% rename from clients/ctl/admin-ui/src/features/common/helpers.ts rename to clients/admin-ui/src/features/common/helpers.ts index 293a938899..2ee7962bcf 100644 --- a/clients/ctl/admin-ui/src/features/common/helpers.ts +++ b/clients/admin-ui/src/features/common/helpers.ts @@ -1,3 +1,7 @@ +/** + * Taken from https://redux-toolkit.js.org/rtk-query/usage-with-typescript#inline-error-handling-example + */ +import { FetchBaseQueryError } from "@reduxjs/toolkit/query"; import { YAMLException } from "js-yaml"; import { narrow } from "narrow-minded"; @@ -13,9 +17,6 @@ import { export { isErrorResult } from "~/types/errors/api"; -export const isYamlException = (error: unknown): error is YAMLException => - narrow({ name: "string" }, error) && error.name === "YAMLException"; - const DEFAULT_ERROR_MESSAGE = "An unexpected error occurred. Please try again."; export const getErrorMessage = ( @@ -41,6 +42,76 @@ export const getErrorMessage = ( return defaultMsg; }; +export const isYamlException = (error: unknown): error is YAMLException => + narrow({ name: "string" }, error) && error.name === "YAMLException"; + +/** + * Type predicate to narrow an unknown error to `FetchBaseQueryError` + */ +export function isFetchBaseQueryError( + error: unknown +): error is FetchBaseQueryError { + return typeof error === "object" && error != null && "status" in error; +} + +/** + * Type predicate to narrow an unknown error to an object with a string 'message' property + */ +export function isErrorWithMessage( + error: unknown +): error is { message: string } { + return ( + typeof error === "object" && + error != null && + "message" in error && + typeof (error as any).message === "string" + ); +} + +// generic error of the structure we expect from the Fidesops backend +interface ResponseError { + data: { + detail: string; + }; +} + +interface ErrorDetail { + loc: string[]; + msg: string; + type: string; +} + +interface ValidationError { + data: { + detail: ErrorDetail[]; + }; +} + +/** + * Custom type predicate to see if the error has details as returned by the Fidesops API + * @param error + * @returns + */ +export function isErrorWithDetail(error: unknown): error is ResponseError { + return ( + typeof error === "object" && + error != null && + "data" in error && + typeof (error as any).data.detail === "string" + ); +} + +export function isErrorWithDetailArray( + error: unknown +): error is ValidationError { + return ( + typeof error === "object" && + error != null && + "data" in error && + Array.isArray((error as any).data.detail) + ); +} + export interface ParsedError { status: number; message: string; diff --git a/clients/admin-ui/src/features/common/hooks/index.ts b/clients/admin-ui/src/features/common/hooks/index.ts new file mode 100644 index 0000000000..845cf6af9b --- /dev/null +++ b/clients/admin-ui/src/features/common/hooks/index.ts @@ -0,0 +1,3 @@ +export * from "./useAlert"; +export * from "./useAPIHelper"; +export * from "./useOutsideClick"; diff --git a/clients/admin-ui/src/features/common/hooks/useAPIHelper.ts b/clients/admin-ui/src/features/common/hooks/useAPIHelper.ts new file mode 100644 index 0000000000..bf66e393d6 --- /dev/null +++ b/clients/admin-ui/src/features/common/hooks/useAPIHelper.ts @@ -0,0 +1,27 @@ +import { isErrorWithDetail, isErrorWithDetailArray } from "common/helpers"; + +import { useAlert } from "./useAlert"; + +/** + * Custom hook for API helper methods + * @returns + */ +export const useAPIHelper = () => { + const { errorAlert } = useAlert(); + + /** + * Display custom error toast notification as a result of an API exception + * @param error + */ + const handleError = (error: any) => { + let errorMsg = "An unexpected error occurred. Please try again."; + if (isErrorWithDetail(error)) { + errorMsg = error.data.detail; + } else if (isErrorWithDetailArray(error)) { + errorMsg = error.data.detail[0].msg; + } + errorAlert(errorMsg); + }; + + return { handleError }; +}; diff --git a/clients/admin-ui/src/features/common/hooks/useAlert.tsx b/clients/admin-ui/src/features/common/hooks/useAlert.tsx new file mode 100644 index 0000000000..f048548788 --- /dev/null +++ b/clients/admin-ui/src/features/common/hooks/useAlert.tsx @@ -0,0 +1,54 @@ +import { + Alert, + AlertDescription, + AlertIcon, + Box, + useToast, +} from "@fidesui/react"; + +/** + * Custom hook for toast notifications + * @returns + */ +export const useAlert = () => { + const toast = useToast(); + const DEFAULT_POSITION = "top"; + + /** + * Display custom error toast notification + * @param description + */ + const errorAlert = (description: string | JSX.Element) => { + toast({ + isClosable: true, + position: DEFAULT_POSITION, + render: () => ( + + + + {description} + + + ), + }); + }; + + /** + * Display custom success toast notification + * @param description + */ + const successAlert = (description: string) => { + toast({ + isClosable: true, + position: DEFAULT_POSITION, + render: () => ( + + + {description} + + ), + }); + }; + + return { errorAlert, successAlert }; +}; diff --git a/clients/admin-ui/src/features/common/hooks/useOutsideClick.ts b/clients/admin-ui/src/features/common/hooks/useOutsideClick.ts new file mode 100644 index 0000000000..d69c90955a --- /dev/null +++ b/clients/admin-ui/src/features/common/hooks/useOutsideClick.ts @@ -0,0 +1,22 @@ +import { LegacyRef, useEffect, useRef } from "react"; + +// eslint-disable-next-line import/prefer-default-export +export const useOutsideClick = (handleClick: () => void) => { + const ref = useRef(undefined) as + | LegacyRef + | undefined; + useEffect(() => { + const handleOutsideClick = (event: MouseEvent) => { + // @ts-ignore + if (!ref.current?.contains(event.target)) { + handleClick(); + } + }; + document.addEventListener("mousedown", handleOutsideClick); + return () => { + document.removeEventListener("mousedown", handleOutsideClick); + }; + }, [ref, handleClick]); + + return { ref }; +}; diff --git a/clients/ctl/admin-ui/src/features/common/nav/NavBar.tsx b/clients/admin-ui/src/features/common/nav/NavBar.tsx similarity index 75% rename from clients/ctl/admin-ui/src/features/common/nav/NavBar.tsx rename to clients/admin-ui/src/features/common/nav/NavBar.tsx index da778c5675..c952265769 100644 --- a/clients/ctl/admin-ui/src/features/common/nav/NavBar.tsx +++ b/clients/admin-ui/src/features/common/nav/NavBar.tsx @@ -2,6 +2,11 @@ import { Flex } from "@fidesui/react"; import dynamic from "next/dynamic"; import React from "react"; +import { + DATASTORE_CONNECTION_ROUTE, + INDEX_ROUTE, + USER_MANAGEMENT_ROUTE, +} from "~/constants"; import { useFeatures } from "~/features/common/features.slice"; // Cross-zone navigation requires building URLs from the current `window.location` @@ -20,6 +25,12 @@ const NavBar = () => { borderColor="gray.100" >