diff --git a/.github/workflows/docker-ephemeral-env.yml b/.github/workflows/docker-ephemeral-env.yml index bc877ae9ae737..41f50acb82d38 100644 --- a/.github/workflows/docker-ephemeral-env.yml +++ b/.github/workflows/docker-ephemeral-env.yml @@ -18,8 +18,6 @@ jobs: shell: bash run: | if [ -n "${{ (secrets.AWS_ACCESS_KEY_ID != '' && - secrets.AWS_ACCESS_KEY_ID != '' && - secrets.AWS_SECRET_ACCESS_KEY != '' && secrets.AWS_SECRET_ACCESS_KEY != '') || '' }}" ]; then echo "has-secrets=1" >> "$GITHUB_OUTPUT" echo "has secrets!" diff --git a/1 b/1 deleted file mode 100644 index 56866025994a3..0000000000000 --- a/1 +++ /dev/null @@ -1,688 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# isort:skip_file -"""Unit tests for Superset""" -import json -import unittest -from tests.integration_tests.fixtures.birth_names_dashboard import ( - load_birth_names_dashboard_with_slices, - load_birth_names_data, -) - -import pytest -from flask import g -from sqlalchemy.orm.session import make_transient - -from tests.integration_tests.fixtures.energy_dashboard import ( - load_energy_table_with_slice, - load_energy_table_data, -) -from tests.integration_tests.test_app import app -from superset.commands.dashboard.importers.v0 import decode_dashboards -from superset import db, security_manager - -from superset.connectors.sqla.models import SqlaTable, SqlMetric, TableColumn -from superset.commands.dashboard.importers.v0 import import_chart, import_dashboard -from superset.commands.dataset.importers.v0 import import_dataset -from superset.models.dashboard import Dashboard -from superset.models.slice import Slice -from superset.utils.core import DatasourceType, get_example_default_schema -from superset.utils.database import get_example_database - -from tests.integration_tests.fixtures.world_bank_dashboard import ( - load_world_bank_dashboard_with_slices, - load_world_bank_data, -) -from .base_tests import SupersetTestCase - - -def delete_imports(): - with app.app_context(): - # Imported data clean up - session = db.session - for slc in session.query(Slice): - if "remote_id" in slc.params_dict: - session.delete(slc) - for dash in session.query(Dashboard): - if "remote_id" in dash.params_dict: - session.delete(dash) - for table in session.query(SqlaTable): - if "remote_id" in table.params_dict: - session.delete(table) - session.commit() - - -@pytest.fixture(autouse=True, scope="module") -def clean_imports(): - yield - delete_imports() - - -class TestImportExport(SupersetTestCase): - """Testing export import functionality for dashboards""" - - def create_slice( - self, - name, - ds_id=None, - id=None, - db_name="examples", - table_name="wb_health_population", - schema=None, - ): - params = { - "num_period_compare": "10", - "remote_id": id, - "datasource_name": table_name, - "database_name": db_name, - "schema": schema, - # Test for trailing commas - "metrics": ["sum__signup_attempt_email", "sum__signup_attempt_facebook"], - } - - if table_name and not ds_id: - table = self.get_table(schema=schema, name=table_name) - if table: - ds_id = table.id - - return Slice( - slice_name=name, - datasource_type=DatasourceType.TABLE, - viz_type="bubble", - params=json.dumps(params), - datasource_id=ds_id, - id=id, - ) - - def create_dashboard(self, title, id=0, slcs=[]): - json_metadata = {"remote_id": id} - return Dashboard( - id=id, - dashboard_title=title, - slices=slcs, - position_json='{"size_y": 2, "size_x": 2}', - slug=f"{title.lower()}_imported", - json_metadata=json.dumps(json_metadata), - published=False, - ) - - def create_table(self, name, schema=None, id=0, cols_names=[], metric_names=[]): - params = {"remote_id": id, "database_name": "examples"} - table = SqlaTable( - id=id, - schema=schema, - table_name=name, - params=json.dumps(params), - ) - for col_name in cols_names: - table.columns.append(TableColumn(column_name=col_name)) - for metric_name in metric_names: - table.metrics.append(SqlMetric(metric_name=metric_name, expression="")) - return table - - def get_slice(self, slc_id): - return db.session.query(Slice).filter_by(id=slc_id).first() - - def get_slice_by_name(self, name): - return db.session.query(Slice).filter_by(slice_name=name).first() - - def get_dash(self, dash_id): - return db.session.query(Dashboard).filter_by(id=dash_id).first() - - def assert_dash_equals( - self, expected_dash, actual_dash, check_position=True, check_slugs=True - ): - if check_slugs: - self.assertEqual(expected_dash.slug, actual_dash.slug) - self.assertEqual(expected_dash.dashboard_title, actual_dash.dashboard_title) - self.assertEqual(len(expected_dash.slices), len(actual_dash.slices)) - expected_slices = sorted(expected_dash.slices, key=lambda s: s.slice_name or "") - actual_slices = sorted(actual_dash.slices, key=lambda s: s.slice_name or "") - for e_slc, a_slc in zip(expected_slices, actual_slices): - self.assert_slice_equals(e_slc, a_slc) - if check_position: - self.assertEqual(expected_dash.position_json, actual_dash.position_json) - - def assert_table_equals(self, expected_ds, actual_ds): - self.assertEqual(expected_ds.table_name, actual_ds.table_name) - self.assertEqual(expected_ds.main_dttm_col, actual_ds.main_dttm_col) - self.assertEqual(expected_ds.schema, actual_ds.schema) - self.assertEqual(len(expected_ds.metrics), len(actual_ds.metrics)) - self.assertEqual(len(expected_ds.columns), len(actual_ds.columns)) - self.assertEqual( - {c.column_name for c in expected_ds.columns}, - {c.column_name for c in actual_ds.columns}, - ) - self.assertEqual( - {m.metric_name for m in expected_ds.metrics}, - {m.metric_name for m in actual_ds.metrics}, - ) - - def assert_datasource_equals(self, expected_ds, actual_ds): - self.assertEqual(expected_ds.datasource_name, actual_ds.datasource_name) - self.assertEqual(expected_ds.main_dttm_col, actual_ds.main_dttm_col) - self.assertEqual(len(expected_ds.metrics), len(actual_ds.metrics)) - self.assertEqual(len(expected_ds.columns), len(actual_ds.columns)) - self.assertEqual( - {c.column_name for c in expected_ds.columns}, - {c.column_name for c in actual_ds.columns}, - ) - self.assertEqual( - {m.metric_name for m in expected_ds.metrics}, - {m.metric_name for m in actual_ds.metrics}, - ) - - def assert_slice_equals(self, expected_slc, actual_slc): - # to avoid bad slice data (no slice_name) - expected_slc_name = expected_slc.slice_name or "" - actual_slc_name = actual_slc.slice_name or "" - self.assertEqual(expected_slc_name, actual_slc_name) - self.assertEqual(expected_slc.datasource_type, actual_slc.datasource_type) - self.assertEqual(expected_slc.viz_type, actual_slc.viz_type) - exp_params = json.loads(expected_slc.params) - actual_params = json.loads(actual_slc.params) - diff_params_keys = ( - "schema", - "database_name", - "datasource_name", - "remote_id", - "import_time", - ) - for k in diff_params_keys: - if k in actual_params: - actual_params.pop(k) - if k in exp_params: - exp_params.pop(k) - self.assertEqual(exp_params, actual_params) - - def assert_only_exported_slc_fields(self, expected_dash, actual_dash): - """only exported json has this params - imported/created dashboard has relationships to other models instead - """ - expected_slices = sorted(expected_dash.slices, key=lambda s: s.slice_name or "") - actual_slices = sorted(actual_dash.slices, key=lambda s: s.slice_name or "") - for e_slc, a_slc in zip(expected_slices, actual_slices): - params = a_slc.params_dict - self.assertEqual(e_slc.datasource.name, params["datasource_name"]) - self.assertEqual(e_slc.datasource.schema, params["schema"]) - self.assertEqual(e_slc.datasource.database.name, params["database_name"]) - - @unittest.skip("Schema needs to be updated") - @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") - def test_export_1_dashboard(self): - self.login("admin") - birth_dash = self.get_dash_by_slug("births") - id_ = birth_dash.id - export_dash_url = f"/dashboard/export_dashboards_form?id={id_}&action=go" - resp = self.client.get(export_dash_url) - exported_dashboards = json.loads( - resp.data.decode("utf-8"), object_hook=decode_dashboards - )["dashboards"] - - birth_dash = self.get_dash_by_slug("births") - self.assert_only_exported_slc_fields(birth_dash, exported_dashboards[0]) - self.assert_dash_equals(birth_dash, exported_dashboards[0]) - self.assertEqual( - id_, - json.loads( - exported_dashboards[0].json_metadata, object_hook=decode_dashboards - )["remote_id"], - ) - - exported_tables = json.loads( - resp.data.decode("utf-8"), object_hook=decode_dashboards - )["datasources"] - self.assertEqual(1, len(exported_tables)) - self.assert_table_equals(self.get_table(name="birth_names"), exported_tables[0]) - - @unittest.skip("Schema needs to be updated") - @pytest.mark.usefixtures( - "load_world_bank_dashboard_with_slices", - "load_birth_names_dashboard_with_slices", - ) - def test_export_2_dashboards(self): - self.login("admin") - birth_dash = self.get_dash_by_slug("births") - world_health_dash = self.get_dash_by_slug("world_health") - export_dash_url = ( - "/dashboard/export_dashboards_form?id={}&id={}&action=go".format( - birth_dash.id, world_health_dash.id - ) - ) - resp = self.client.get(export_dash_url) - resp_data = json.loads(resp.data.decode("utf-8"), object_hook=decode_dashboards) - exported_dashboards = sorted( - resp_data.get("dashboards"), key=lambda d: d.dashboard_title - ) - self.assertEqual(2, len(exported_dashboards)) - - birth_dash = self.get_dash_by_slug("births") - self.assert_only_exported_slc_fields(birth_dash, exported_dashboards[0]) - self.assert_dash_equals(birth_dash, exported_dashboards[0]) - self.assertEqual( - birth_dash.id, json.loads(exported_dashboards[0].json_metadata)["remote_id"] - ) - - world_health_dash = self.get_dash_by_slug("world_health") - self.assert_only_exported_slc_fields(world_health_dash, exported_dashboards[1]) - self.assert_dash_equals(world_health_dash, exported_dashboards[1]) - self.assertEqual( - world_health_dash.id, - json.loads(exported_dashboards[1].json_metadata)["remote_id"], - ) - - exported_tables = sorted( - resp_data.get("datasources"), key=lambda t: t.table_name - ) - self.assertEqual(2, len(exported_tables)) - self.assert_table_equals(self.get_table(name="birth_names"), exported_tables[0]) - self.assert_table_equals( - self.get_table(name="wb_health_population"), exported_tables[1] - ) - - @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices") - def test_import_1_slice(self): - expected_slice = self.create_slice( - "Import Me", id=10001, schema=get_example_default_schema() - ) - slc_id = import_chart(expected_slice, None, import_time=1989) - slc = self.get_slice(slc_id) - self.assertEqual(slc.datasource.perm, slc.perm) - self.assert_slice_equals(expected_slice, slc) - - table_id = self.get_table(name="wb_health_population").id - self.assertEqual(table_id, self.get_slice(slc_id).datasource_id) - - @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices") - def test_import_2_slices_for_same_table(self): - schema = get_example_default_schema() - table_id = self.get_table(name="wb_health_population").id - slc_1 = self.create_slice( - "Import Me 1", ds_id=table_id, id=10002, schema=schema - ) - slc_id_1 = import_chart(slc_1, None) - slc_2 = self.create_slice( - "Import Me 2", ds_id=table_id, id=10003, schema=schema - ) - slc_id_2 = import_chart(slc_2, None) - - imported_slc_1 = self.get_slice(slc_id_1) - imported_slc_2 = self.get_slice(slc_id_2) - self.assertEqual(table_id, imported_slc_1.datasource_id) - self.assert_slice_equals(slc_1, imported_slc_1) - self.assertEqual(imported_slc_1.datasource.perm, imported_slc_1.perm) - - self.assertEqual(table_id, imported_slc_2.datasource_id) - self.assert_slice_equals(slc_2, imported_slc_2) - self.assertEqual(imported_slc_2.datasource.perm, imported_slc_2.perm) - - def test_import_slices_override(self): - schema = get_example_default_schema() - slc = self.create_slice("Import Me New", id=10005, schema=schema) - slc_1_id = import_chart(slc, None, import_time=1990) - slc.slice_name = "Import Me New" - imported_slc_1 = self.get_slice(slc_1_id) - slc_2 = self.create_slice("Import Me New", id=10005, schema=schema) - slc_2_id = import_chart(slc_2, imported_slc_1, import_time=1990) - self.assertEqual(slc_1_id, slc_2_id) - imported_slc_2 = self.get_slice(slc_2_id) - self.assert_slice_equals(slc, imported_slc_2) - - def test_import_empty_dashboard(self): - empty_dash = self.create_dashboard("empty_dashboard", id=10001) - imported_dash_id = import_dashboard(empty_dash, import_time=1989) - imported_dash = self.get_dash(imported_dash_id) - self.assert_dash_equals(empty_dash, imported_dash, check_position=False) - - @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices") - def test_import_dashboard_1_slice(self): - slc = self.create_slice( - "health_slc", id=10006, schema=get_example_default_schema() - ) - dash_with_1_slice = self.create_dashboard( - "dash_with_1_slice", slcs=[slc], id=10002 - ) - dash_with_1_slice.position_json = """ - {{"DASHBOARD_VERSION_KEY": "v2", - "DASHBOARD_CHART_TYPE-{0}": {{ - "type": "CHART", - "id": {0}, - "children": [], - "meta": {{ - "width": 4, - "height": 50, - "chartId": {0} - }} - }} - }} - """.format( - slc.id - ) - imported_dash_id = import_dashboard(dash_with_1_slice, import_time=1990) - imported_dash = self.get_dash(imported_dash_id) - - expected_dash = self.create_dashboard("dash_with_1_slice", slcs=[slc], id=10002) - make_transient(expected_dash) - self.assert_dash_equals( - expected_dash, imported_dash, check_position=False, check_slugs=False - ) - self.assertEqual( - { - "remote_id": 10002, - "import_time": 1990, - "native_filter_configuration": [], - }, - json.loads(imported_dash.json_metadata), - ) - - expected_position = dash_with_1_slice.position - # new slice id (auto-incremental) assigned on insert - # id from json is used only for updating position with new id - meta = expected_position["DASHBOARD_CHART_TYPE-10006"]["meta"] - meta["chartId"] = imported_dash.slices[0].id - self.assertEqual(expected_position, imported_dash.position) - - @pytest.mark.usefixtures("load_energy_table_with_slice") - def test_import_dashboard_2_slices(self): - schema = get_example_default_schema() - e_slc = self.create_slice( - "e_slc", id=10007, table_name="energy_usage", schema=schema - ) - b_slc = self.create_slice( - "b_slc", id=10008, table_name="birth_names", schema=schema - ) - dash_with_2_slices = self.create_dashboard( - "dash_with_2_slices", slcs=[e_slc, b_slc], id=10003 - ) - dash_with_2_slices.json_metadata = json.dumps( - { - "remote_id": 10003, - "expanded_slices": { - f"{e_slc.id}": True, - f"{b_slc.id}": False, - }, - # mocked legacy filter_scope metadata - "filter_scopes": { - str(e_slc.id): { - "region": {"scope": ["ROOT_ID"], "immune": [b_slc.id]} - } - }, - } - ) - - imported_dash_id = import_dashboard(dash_with_2_slices, import_time=1991) - imported_dash = self.get_dash(imported_dash_id) - - expected_dash = self.create_dashboard( - "dash_with_2_slices", slcs=[e_slc, b_slc], id=10003 - ) - make_transient(expected_dash) - self.assert_dash_equals( - imported_dash, expected_dash, check_position=False, check_slugs=False - ) - i_e_slc = self.get_slice_by_name("e_slc") - i_b_slc = self.get_slice_by_name("b_slc") - expected_json_metadata = { - "remote_id": 10003, - "import_time": 1991, - "expanded_slices": { - f"{i_e_slc.id}": True, - f"{i_b_slc.id}": False, - }, - "native_filter_configuration": [], - } - self.assertEqual( - expected_json_metadata, json.loads(imported_dash.json_metadata) - ) - - @pytest.mark.usefixtures("load_energy_table_with_slice") - def test_import_override_dashboard_2_slices(self): - schema = get_example_default_schema() - e_slc = self.create_slice( - "e_slc", id=10009, table_name="energy_usage", schema=schema - ) - b_slc = self.create_slice( - "b_slc", id=10010, table_name="birth_names", schema=schema - ) - dash_to_import = self.create_dashboard( - "override_dashboard", slcs=[e_slc, b_slc], id=10004 - ) - imported_dash_id_1 = import_dashboard(dash_to_import, import_time=1992) - - # create new instances of the slices - e_slc = self.create_slice( - "e_slc", id=10009, table_name="energy_usage", schema=schema - ) - b_slc = self.create_slice( - "b_slc", id=10010, table_name="birth_names", schema=schema - ) - c_slc = self.create_slice( - "c_slc", id=10011, table_name="birth_names", schema=schema - ) - dash_to_import_override = self.create_dashboard( - "override_dashboard_new", slcs=[e_slc, b_slc, c_slc], id=10004 - ) - imported_dash_id_2 = import_dashboard(dash_to_import_override, import_time=1992) - - # override doesn't change the id - self.assertEqual(imported_dash_id_1, imported_dash_id_2) - expected_dash = self.create_dashboard( - "override_dashboard_new", slcs=[e_slc, b_slc, c_slc], id=10004 - ) - make_transient(expected_dash) - imported_dash = self.get_dash(imported_dash_id_2) - self.assert_dash_equals( - expected_dash, imported_dash, check_position=False, check_slugs=False - ) - self.assertEqual( - { - "remote_id": 10004, - "import_time": 1992, - "native_filter_configuration": [], - }, - json.loads(imported_dash.json_metadata), - ) - - def test_import_new_dashboard_slice_reset_ownership(self): - admin_user = security_manager.find_user(username="admin") - self.assertTrue(admin_user) - gamma_user = security_manager.find_user(username="gamma") - self.assertTrue(gamma_user) - g.user = gamma_user - - dash_with_1_slice = self._create_dashboard_for_import(id_=10200) - # set another user as an owner of importing dashboard - dash_with_1_slice.created_by = admin_user - dash_with_1_slice.changed_by = admin_user - dash_with_1_slice.owners = [admin_user] - - imported_dash_id = import_dashboard(dash_with_1_slice) - imported_dash = self.get_dash(imported_dash_id) - self.assertEqual(imported_dash.created_by, gamma_user) - self.assertEqual(imported_dash.changed_by, gamma_user) - self.assertEqual(imported_dash.owners, [gamma_user]) - - imported_slc = imported_dash.slices[0] - self.assertEqual(imported_slc.created_by, gamma_user) - self.assertEqual(imported_slc.changed_by, gamma_user) - self.assertEqual(imported_slc.owners, [gamma_user]) - - def test_import_override_dashboard_slice_reset_ownership(self): - admin_user = security_manager.find_user(username="admin") - self.assertTrue(admin_user) - gamma_user = security_manager.find_user(username="gamma") - self.assertTrue(gamma_user) - g.user = gamma_user - - dash_with_1_slice = self._create_dashboard_for_import(id_=10300) - - imported_dash_id = import_dashboard(dash_with_1_slice) - imported_dash = self.get_dash(imported_dash_id) - self.assertEqual(imported_dash.created_by, gamma_user) - self.assertEqual(imported_dash.changed_by, gamma_user) - self.assertEqual(imported_dash.owners, [gamma_user]) - - imported_slc = imported_dash.slices[0] - self.assertEqual(imported_slc.created_by, gamma_user) - self.assertEqual(imported_slc.changed_by, gamma_user) - self.assertEqual(imported_slc.owners, [gamma_user]) - - # re-import with another user shouldn't change the permissions - g.user = admin_user - - dash_with_1_slice = self._create_dashboard_for_import(id_=10300) - - imported_dash_id = import_dashboard(dash_with_1_slice) - imported_dash = self.get_dash(imported_dash_id) - self.assertEqual(imported_dash.created_by, gamma_user) - self.assertEqual(imported_dash.changed_by, gamma_user) - self.assertEqual(imported_dash.owners, [gamma_user]) - - imported_slc = imported_dash.slices[0] - self.assertEqual(imported_slc.created_by, gamma_user) - self.assertEqual(imported_slc.changed_by, gamma_user) - self.assertEqual(imported_slc.owners, [gamma_user]) - - def _create_dashboard_for_import(self, id_=10100): - slc = self.create_slice( - "health_slc" + str(id_), id=id_ + 1, schema=get_example_default_schema() - ) - dash_with_1_slice = self.create_dashboard( - "dash_with_1_slice" + str(id_), slcs=[slc], id=id_ + 2 - ) - dash_with_1_slice.position_json = """ - {{"DASHBOARD_VERSION_KEY": "v2", - "DASHBOARD_CHART_TYPE-{0}": {{ - "type": "CHART", - "id": {0}, - "children": [], - "meta": {{ - "width": 4, - "height": 50, - "chartId": {0} - }} - }} - }} - """.format( - slc.id - ) - return dash_with_1_slice - - def test_import_table_no_metadata(self): - schema = get_example_default_schema() - db_id = get_example_database().id - table = self.create_table("pure_table", id=10001, schema=schema) - imported_id = import_dataset(table, db_id, import_time=1989) - imported = self.get_table_by_id(imported_id) - self.assert_table_equals(table, imported) - - def test_import_table_1_col_1_met(self): - schema = get_example_default_schema() - table = self.create_table( - "table_1_col_1_met", - id=10002, - cols_names=["col1"], - metric_names=["metric1"], - schema=schema, - ) - db_id = get_example_database().id - imported_id = import_dataset(table, db_id, import_time=1990) - imported = self.get_table_by_id(imported_id) - self.assert_table_equals(table, imported) - self.assertEqual( - { - "remote_id": 10002, - "import_time": 1990, - "database_name": "examples", - }, - json.loads(imported.params), - ) - - def test_import_table_2_col_2_met(self): - schema = get_example_default_schema() - table = self.create_table( - "table_2_col_2_met", - id=10003, - cols_names=["c1", "c2"], - metric_names=["m1", "m2"], - schema=schema, - ) - db_id = get_example_database().id - imported_id = import_dataset(table, db_id, import_time=1991) - - imported = self.get_table_by_id(imported_id) - self.assert_table_equals(table, imported) - - def test_import_table_override(self): - schema = get_example_default_schema() - table = self.create_table( - "table_override", - id=10003, - cols_names=["col1"], - metric_names=["m1"], - schema=schema, - ) - db_id = get_example_database().id - imported_id = import_dataset(table, db_id, import_time=1991) - - table_over = self.create_table( - "table_override", - id=10003, - cols_names=["new_col1", "col2", "col3"], - metric_names=["new_metric1"], - schema=schema, - ) - imported_over_id = import_dataset(table_over, db_id, import_time=1992) - - imported_over = self.get_table_by_id(imported_over_id) - self.assertEqual(imported_id, imported_over.id) - expected_table = self.create_table( - "table_override", - id=10003, - metric_names=["new_metric1", "m1"], - cols_names=["col1", "new_col1", "col2", "col3"], - schema=schema, - ) - self.assert_table_equals(expected_table, imported_over) - - def test_import_table_override_identical(self): - schema = get_example_default_schema() - table = self.create_table( - "copy_cat", - id=10004, - cols_names=["new_col1", "col2", "col3"], - metric_names=["new_metric1"], - schema=schema, - ) - db_id = get_example_database().id - imported_id = import_dataset(table, db_id, import_time=1993) - - copy_table = self.create_table( - "copy_cat", - id=10004, - cols_names=["new_col1", "col2", "col3"], - metric_names=["new_metric1"], - schema=schema, - ) - imported_id_copy = import_dataset(copy_table, db_id, import_time=1994) - - self.assertEqual(imported_id, imported_id_copy) - self.assert_table_equals(copy_table, self.get_table_by_id(imported_id)) - - -if __name__ == "__main__": - unittest.main() diff --git a/CHANGELOG.md b/CHANGELOG.md index 2912302eaf251..b44b304b38fd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ under the License. ## Change Log +- [3.0.3](#303-tue-jan-9-164807-2023--0300) - [3.0.2](#302-mon-nov-20-073838-2023--0500) - [3.0.1](#301-tue-oct-13-103221-2023--0700) - [3.0.0](#300-thu-aug-24-133627-2023--0600) @@ -35,6 +36,66 @@ under the License. - [1.4.2](#142-sat-mar-19-000806-2022-0200) - [1.4.1](#141) +### 3.0.3 (Tue Jan 9 16:48:07 2023 -0300) + +**Fixes** + +- [#26429](https://github.com/apache/superset/pull/26429) fix(post-processing): handle missing values in cumulative operator (@villebro) +- [#26424](https://github.com/apache/superset/pull/26424) fix(translations): Clear all (@capping) +- [#26404](https://github.com/apache/superset/pull/26404) fix(plugin-chart-echarts): support forced categorical x-axis (@villebro) +- [#26415](https://github.com/apache/superset/pull/26415) fix: In chart gallery thumbnail is rendered in case of no example in #16707 (@sivasathyaseeelan) +- [#26393](https://github.com/apache/superset/pull/26393) fix(chart): Resolve incorrect column customization when switching metrics in table chart (@soniagtm) +- [#26313](https://github.com/apache/superset/pull/26313) fix(dashboard): narrow empty drop area (@justinpark) +- [#26410](https://github.com/apache/superset/pull/26410) fix(dashboard): Chart menu disable is fixed on chart-fullscreen in issue #25992 (@sivasathyaseeelan) +- [#26362](https://github.com/apache/superset/pull/26362) fix: Reactivates native filters E2E tests (@michael-s-molina) +- [#26353](https://github.com/apache/superset/pull/26353) fix(SelectControl): select zero value (@rekilina) +- [#26302](https://github.com/apache/superset/pull/26302) fix: Invalid references in the basic template (@michael-s-molina) +- [#26380](https://github.com/apache/superset/pull/26380) fix: Removes non-existent columns in the 2018 FCC Survey dataset (@michael-s-molina) +- [#26151](https://github.com/apache/superset/pull/26151) fix(chart): Set max row limit + removed the option to use an empty row limit value (@CorbinBullard) +- [#26333](https://github.com/apache/superset/pull/26333) fix(logging): Add logging of change_dashboard_filter event for native dashboard filters (@john-bodley) +- [#26326](https://github.com/apache/superset/pull/26326) fix(accessibility): Enable tabbing on sort header of table chart (@arunthirumani) +- [#26340](https://github.com/apache/superset/pull/26340) fix(dashboard): Don't switch to first tab when directPathToChild changes (@kgabryje) +- [#26283](https://github.com/apache/superset/pull/26283) fix(redshift): convert_dttm method for redshift dataset and tests (@gaurav7261) +- [#26281](https://github.com/apache/superset/pull/26281) fix(sql lab): Use quote_schema instead of quote method to format schema name (@guenp) +- [#25967](https://github.com/apache/superset/pull/25967) fix(typings): model_id is a multiple option (@gnought) +- [#26279](https://github.com/apache/superset/pull/26279) fix: Cannot expand initially hidden SQL Lab tab (@michael-s-molina) +- [#26269](https://github.com/apache/superset/pull/26269) fix(plugin-chart-echarts): use scale for truncating x-axis (@villebro) +- [#26264](https://github.com/apache/superset/pull/26264) fix: Stacked charts with numerical columns (@michael-s-molina) +- [#26187](https://github.com/apache/superset/pull/26187) fix: bump pyarrow constraints (CVE-2023-47248) (@cwegener) +- [#26215](https://github.com/apache/superset/pull/26215) fix(plugin-chart-echarts): support truncated numeric x-axis (@villebro) +- [#26199](https://github.com/apache/superset/pull/26199) fix(chart-filter): Avoid column denormalization if not enabled (@Vitor-Avila) +- [#26211](https://github.com/apache/superset/pull/26211) fix: support custom links in markdown (@villebro) +- [#26189](https://github.com/apache/superset/pull/26189) fix(dashboard): title formatting (@nytai) +- [#26207](https://github.com/apache/superset/pull/26207) fix: Includes 90° x-axis label rotation (@michael-s-molina) +- [#26157](https://github.com/apache/superset/pull/26157) fix(init-job): Fix envFrom for init job in helm chart (@sumagoudb) +- [#25878](https://github.com/apache/superset/pull/25878) fix(embedded): Hide sensitive payload data from guest users (@jfrag1) +- [#25894](https://github.com/apache/superset/pull/25894) fix(Alerts/Reports): allow use of ";" separator in slack recipient entry (@rtexelm) +- [#26116](https://github.com/apache/superset/pull/26116) fix(database-import): Support importing a DB connection with a version set (@Vitor-Avila) +- [#26154](https://github.com/apache/superset/pull/26154) fix: set label on adhoc column should persist (@betodealmeida) +- [#26140](https://github.com/apache/superset/pull/26140) fix(annotations): time grain column (@betodealmeida) +- [#23916](https://github.com/apache/superset/pull/23916) fix: remove default secret key from helm (@dpgaspar) +- [#26120](https://github.com/apache/superset/pull/26120) fix: alias column when fetching values (@betodealmeida) +- [#26106](https://github.com/apache/superset/pull/26106) fix: flaky test_explore_json_async test v2 (@villebro) +- [#26091](https://github.com/apache/superset/pull/26091) fix: bump node-fetch to 2.6.7 (@dpgaspar) +- [#26087](https://github.com/apache/superset/pull/26087) fix(plugin-chart-echarts): support numerical x-axis (@villebro) +- [#26059](https://github.com/apache/superset/pull/26059) fix: Flaky test_explore_json_async test (@michael-s-molina) +- [#26023](https://github.com/apache/superset/pull/26023) fix: Prevent cached bootstrap data from leaking between users w/ same first/last name (@jfrag1) +- [#26060](https://github.com/apache/superset/pull/26060) fix: Optimize fetching samples logic (@john-bodley) +- [#26010](https://github.com/apache/superset/pull/26010) fix: Remove annotation Fuzzy to get french translation (@aehanno) +- [#26005](https://github.com/apache/superset/pull/26005) fix(security): restore default value of SESSION_COOKIE_SECURE to False (@sfirke) +- [#25883](https://github.com/apache/superset/pull/25883) fix(horizontal filter bar filter labels): Increase max-width to 96px (@rtexelm) + +**Others** + +- [#26312](https://github.com/apache/superset/pull/26312) chore(Embedded): Avoid creating a filter key for guest users (@Vitor-Avila) +- [#26317](https://github.com/apache/superset/pull/26317) chore: Adds a tooltip for the alert's SQL input (@michael-s-molina) +- [#26310](https://github.com/apache/superset/pull/26310) chore: Disables minor ticks by default (@michael-s-molina) +- [#26287](https://github.com/apache/superset/pull/26287) chore: update changelog for 2.1.3 (@eschutho) +- [#26251](https://github.com/apache/superset/pull/26251) chore: improve CSP add base uri restriction (@dpgaspar) +- [#26208](https://github.com/apache/superset/pull/26208) chore: Adds note about numerical x-axis (@michael-s-molina) +- [#26158](https://github.com/apache/superset/pull/26158) chore: Clean up the examples dashboards (@michael-s-molina) +- [#25931](https://github.com/apache/superset/pull/25931) chore(deps): bump pillow deps (@gnought) + ### 3.0.2 (Mon Nov 20 07:38:38 2023 -0500) **Fixes** @@ -906,16 +967,19 @@ under the License. - [#23108](https://github.com/apache/superset/pull/23108) chore: Remove yarn.lock from the root folder (@EugeneTorap) ### 2.1.3 (Fri Dec 8 16:36:51 2023 -0700) + **Database Migrations** **Features** **Fixes** + - [#25658](https://github.com/apache/superset/pull/25658) fix: improve upload ZIP file validation (@dpgaspar) - [#25779](https://github.com/apache/superset/pull/25779) fix: DB-specific quoting in Jinja macro (@betodealmeida) - [#25843](https://github.com/apache/superset/pull/25843) fix: remove `update_charts_owners` (@betodealmeida) **Others** + - [#23862](https://github.com/apache/superset/pull/23862) chore: Use nh3 lib instead of bleach (@EugeneTorap) - [#23965](https://github.com/apache/superset/pull/23965) chore: bump werkzeug and Flask (@dpgaspar) - [#24033](https://github.com/apache/superset/pull/24033) chore: Update mypy and fix stubs issue (@EugeneTorap) @@ -923,11 +987,13 @@ under the License. - [#24324](https://github.com/apache/superset/pull/24324) chore: rate limit requests (@betodealmeida) ### 2.1.2 (Wed Oct 18 16:59:30 2023 -0700) + **Database Migrations** **Features** **Fixes** + - [#25150](https://github.com/apache/superset/pull/25150) fix: Chart series limit doesn't work for some databases (@KSPT-taylorjohn) - [#25014](https://github.com/apache/superset/pull/25014) fix: CTE queries with non-SELECT statements (@dpgaspar) - [#24849](https://github.com/apache/superset/pull/24849) fix: validation errors appearing after ssh tunnel switch (@hughhhh) @@ -936,6 +1002,7 @@ under the License. - [#24317](https://github.com/apache/superset/pull/24317) fix: update order of build for testing a release (@eschutho) **Others** + - [#24826](https://github.com/apache/superset/pull/24826) chore: remove CssTemplate and Annotation access from gamma role (@lilykuang) - [#23680](https://github.com/apache/superset/pull/23680) chore: bump wtforms and add missing flask-limiter (@dpgaspar) - [#24758](https://github.com/apache/superset/pull/24758) chore(view_api): return application/json as content-type for api/v1/form_data endpoint (@zephyring) diff --git a/RESOURCES/FEATURE_FLAGS.md b/RESOURCES/FEATURE_FLAGS.md index 4b78d7e99729a..5c286ffa96487 100644 --- a/RESOURCES/FEATURE_FLAGS.md +++ b/RESOURCES/FEATURE_FLAGS.md @@ -42,11 +42,8 @@ These features are **finished** but currently being tested. They are usable, but - ALLOW_FULL_CSV_EXPORT - CACHE_IMPERSONATION - CONFIRM_DASHBOARD_DIFF -- DASHBOARD_VIRTUALIZATION -- DRILL_BY - DRILL_TO_DETAIL - DYNAMIC_PLUGINS: [(docs)](https://superset.apache.org/docs/installation/running-on-kubernetes) -- ENABLE_JAVASCRIPT_CONTROLS - ESTIMATE_QUERY_COST - GENERIC_CHART_AXES - GLOBAL_ASYNC_QUERIES [(docs)](https://github.com/apache/superset/blob/master/CONTRIBUTING.md#async-chart-queries) @@ -64,10 +61,11 @@ These features flags are **safe for production**. They have been tested and will - ALERTS_ATTACH_REPORTS - ALLOW_ADHOC_SUBQUERY -- DASHBOARD_CROSS_FILTERS - DASHBOARD_RBAC [(docs)](https://superset.apache.org/docs/creating-charts-dashboards/first-dashboard#manage-access-to-dashboards) +- DASHBOARD_VIRTUALIZATION - DATAPANEL_CLOSED_BY_DEFAULT - DISABLE_LEGACY_DATASOURCE_EDITOR +- DRILL_BY - DRUID_JOINS - EMBEDDABLE_CHARTS - EMBEDDED_SUPERSET @@ -85,11 +83,10 @@ These features flags currently default to True and **will be removed in a future [//]: # "PLEASE KEEP THE LIST SORTED ALPHABETICALLY" +- DASHBOARD_CROSS_FILTERS - DASHBOARD_FILTERS_EXPERIMENTAL - DASHBOARD_NATIVE_FILTERS -- ENABLE_EXPLORE_JSON_CSRF_PROTECTION -- ENABLE_TEMPLATE_REMOVE_FILTERS +- ENABLE_JAVASCRIPT_CONTROLS - GENERIC_CHART_AXES - KV_STORE -- REMOVE_SLICE_LEVEL_LABEL_COLORS - VERSIONED_EXPORT diff --git a/UPDATING.md b/UPDATING.md index 584be223a5fc2..7e5e2ea472d75 100644 --- a/UPDATING.md +++ b/UPDATING.md @@ -24,18 +24,22 @@ assists people when migrating to a new version. ## Next -- [26034](https://github.com/apache/superset/issues/26034): Fixes a problem where numeric x-axes were being treated as categorical values. As a consequence of that, the way labels are displayed might change given that ECharts has a different treatment for numerical and categorical values. To revert to the old behavior, users need to manually convert numerical columns to text so that they are treated as categories. Check https://github.com/apache/superset/issues/26159 for more details. - [24657](https://github.com/apache/superset/pull/24657): Bumps the cryptography package to augment the OpenSSL security vulnerability. - [26450](https://github.com/apache/superset/pull/26450): Deprecates the `KV_STORE` feature flag and its related assets such as the API endpoint and `keyvalue` table. The main dependency of this feature is the `SHARE_QUERIES_VIA_KV_STORE` feature flag which allows sharing SQL Lab queries without the necessity of saving the query. Our intention is to use the permalink feature to implement this use case before 5.0 and that's why we are deprecating the feature flag now. ### Breaking Changes +- [26344](https://github.com/apache/superset/issues/26344): Removes the deprecated `ENABLE_EXPLORE_JSON_CSRF_PROTECTION` feature flag. The previous value of the feature flag was `False` and now the feature is permanently removed. +- [26345](https://github.com/apache/superset/issues/26345): Removes the deprecated `ENABLE_TEMPLATE_REMOVE_FILTERS` feature flag. The previous value of the feature flag was `True` and now the feature is permanently enabled. +- [26346](https://github.com/apache/superset/issues/26346): Removes the deprecated `REMOVE_SLICE_LEVEL_LABEL_COLORS` feature flag. The previous value of the feature flag was `False` and now the feature is permanently removed. - [26348](https://github.com/apache/superset/issues/26348): Removes the deprecated `CLIENT_CACHE` feature flag. The previous value of the feature flag was `False` and now the feature is permanently removed. - [26349](https://github.com/apache/superset/issues/26349): Removes the deprecated `DASHBOARD_CACHE` feature flag. The previous value of the feature flag was `False` and now the feature is permanently removed. - [26369](https://github.com/apache/superset/issues/26369): Removes the Filter Sets feature including the deprecated `DASHBOARD_NATIVE_FILTERS_SET` feature flag and all related API endpoints. The feature is permanently removed as it was not being actively maintained, it was not widely used, and it was full of bugs. We also considered that if we were to provide a similar feature, it would be better to re-implement it from scratch given the amount of technical debt that the current implementation has. The previous value of the feature flag was `False` and now the feature is permanently removed. - [26343](https://github.com/apache/superset/issues/26343): Removes the deprecated `ENABLE_EXPLORE_DRAG_AND_DROP` feature flag. The previous value of the feature flag was `True` and now the feature is permanently enabled. - [26331](https://github.com/apache/superset/issues/26331): Removes the deprecated `DISABLE_DATASET_SOURCE_EDIT` feature flag. The previous value of the feature flag was `False` and now the feature is permanently removed. +- [26636](https://github.com/apache/superset/issues/26636): Sets the `DASHBOARD_VIRTUALIZATION` feature flag to `True` by default. This feature was introduced by [21438](https://github.com/apache/superset/pull/21438) and will enable virtualization when rendering a dashboard's charts in an attempt to reduce the number of elements (DOM nodes) rendered at once. This is especially useful for large dashboards. +- [26637](https://github.com/apache/superset/issues/26637): Sets the `DRILL_BY` feature flag to `True` by default given that the feature has been tested for a while and reached a stable state. ### Potential Downtime @@ -45,6 +49,10 @@ assists people when migrating to a new version. - [24982](https://github.com/apache/superset/pull/24982): By default, physical datasets on Oracle-like dialects like Snowflake will now use denormalized column names. However, existing datasets won't be affected. To change this behavior, the "Advanced" section on the dataset modal has a "Normalize column names" flag which can be changed to change this behavior. +## 3.0.3 + +- [26034](https://github.com/apache/superset/issues/26034): Fixes a problem where numeric x-axes were being treated as categorical values. As a consequence of that, the way labels are displayed might change given that ECharts has a different treatment for numerical and categorical values. To revert to the old behavior, users need to manually convert numerical columns to text so that they are treated as categories. Check https://github.com/apache/superset/issues/26159 for more details. + ## 3.0.0 - [25053](https://github.com/apache/superset/pull/25053): Extends the `ab_user.email` column from 64 to 320 characters which has an associated unique key constraint. This will be problematic for MySQL metadata databases which use the InnoDB storage engine with the `innodb_large_prefix` parameter disabled as the key prefix limit is 767 bytes. Enabling said parameter and ensuring that the table uses either the `DYNAMIC` or `COMPRESSED` row format should remedy the problem. See [here](https://dev.mysql.com/doc/refman/5.7/en/innodb-limits.html) for more details. diff --git a/docs/docs/installation/configuring-superset.mdx b/docs/docs/installation/configuring-superset.mdx index 820feaeec9434..30bc2f281cd36 100644 --- a/docs/docs/installation/configuring-superset.mdx +++ b/docs/docs/installation/configuring-superset.mdx @@ -358,7 +358,6 @@ You can enable or disable features with flag from `superset_config.py`: ```python FEATURE_FLAGS = { - 'ENABLE_EXPLORE_JSON_CSRF_PROTECTION': False, 'PRESTO_EXPAND_DATA': False, } ``` diff --git a/docs/package.json b/docs/package.json index 1c8342dd27db4..5ac908c3af90c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -25,13 +25,13 @@ "@docusaurus/preset-classic": "^2.4.3", "@emotion/core": "^10.1.1", "@emotion/styled": "^10.0.27", - "@mdx-js/react": "^1.6.22", + "@mdx-js/react": "^3.0.0", "@saucelabs/theme-github-codeblock": "^0.1.1", "@superset-ui/style": "^0.14.23", "@svgr/webpack": "^5.5.0", "antd": "^4.19.3", "buffer": "^6.0.3", - "clsx": "^1.1.1", + "clsx": "^2.1.0", "docusaurus-plugin-less": "^2.0.2", "file-loader": "^6.2.0", "less": "^4.2.0", @@ -41,14 +41,14 @@ "react-dom": "^17.0.1", "react-github-btn": "^1.2.0", "stream": "^0.0.2", - "swagger-ui-react": "^4.1.3", + "swagger-ui-react": "^5.11.0", "url-loader": "^4.1.1" }, "devDependencies": { "@docusaurus/module-type-aliases": "^2.4.1", - "@tsconfig/docusaurus": "^1.0.6", + "@tsconfig/docusaurus": "^2.0.2", "@types/react": "^17.0.42", - "typescript": "^4.3.5", + "typescript": "^5.3.3", "webpack": "^5.76.0" }, "browserslist": { diff --git a/docs/yarn.lock b/docs/yarn.lock index b25a344c92773..7fc5b3393270c 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -2455,23 +2455,15 @@ resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== -"@babel/runtime-corejs3@^7.11.2", "@babel/runtime-corejs3@^7.16.3": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.9.tgz#3d02d0161f0fbf3ada8e88159375af97690f4055" - integrity sha512-WxYHHUWF2uZ7Hp1K+D1xQgbgkGUfA+5UPOegEXGt2Y5SMog/rYCVaifLZDbw8UkNXozEqqrZTy6bglL7xTaCOw== +"@babel/runtime-corejs3@^7.18.6", "@babel/runtime-corejs3@^7.20.7", "@babel/runtime-corejs3@^7.22.15", "@babel/runtime-corejs3@^7.23.7": + version "7.23.8" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.23.8.tgz#b8aa3d47570bdd08fed77fdfd69542118af0df26" + integrity sha512-2ZzmcDugdm0/YQKFVYsXiwUN7USPX8PM7cytpb4PFl87fM+qYPSvTZX//8tyeJB1j0YDmafBJEbl5f8NfLyuKw== dependencies: - core-js-pure "^3.20.2" - regenerator-runtime "^0.13.4" - -"@babel/runtime-corejs3@^7.18.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.21.0.tgz#6e4939d9d9789ff63e2dc58e88f13a3913a24eba" - integrity sha512-TDD4UJzos3JJtM+tHX+w2Uc+KWj7GV+VKKFdMVd2Rx8sdA19hcc3P3AHFYd5LVOw+pYuSd5lICC3gm52B6Rwxw== - dependencies: - core-js-pure "^3.25.1" - regenerator-runtime "^0.13.11" + core-js-pure "^3.30.2" + regenerator-runtime "^0.14.0" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.13", "@babel/runtime@^7.15.4", "@babel/runtime@^7.3.1", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.13", "@babel/runtime@^7.3.1", "@babel/runtime@^7.8.4": version "7.16.3" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.3.tgz" integrity sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ== @@ -2578,10 +2570,10 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" -"@braintree/sanitize-url@^5.0.2": - version "5.0.2" - resolved "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-5.0.2.tgz" - integrity sha512-NBEJlHWrhQucLhZGHtSxM2loSaNUMajC7KOYJLyfcdW/6goVoff2HoYI3bz8YCDN0wKGbxtUL0gx2dvHpvnWlw== +"@braintree/sanitize-url@=7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-7.0.0.tgz#8899d8e68a1b3f6933d4ad57a263fd3cf1d34d8a" + integrity sha512-GMu2OJiTd1HSe74bbJYQnVvELANpYiGFZELyyTM1CR0sdv5ReQAcJ/c/8pIrPab3lO11+D+EpuGLUxqz+y832g== "@colors/colors@1.5.0": version "1.5.0" @@ -3164,6 +3156,11 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== +"@fastify/busboy@^2.0.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.0.tgz#0709e9f4cb252351c609c6e6d8d6779a8d25edff" + integrity sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA== + "@hapi/hoek@^9.0.0": version "9.2.1" resolved "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz" @@ -3286,6 +3283,13 @@ resolved "https://registry.npmjs.org/@mdx-js/react/-/react-1.6.22.tgz" integrity sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg== +"@mdx-js/react@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-3.0.0.tgz#eaccaa8d6a7736b19080aff5a70448a7ba692271" + integrity sha512-nDctevR9KyYFyV+m+/+S4cpzCWHqj+iHDHq3QrsWezcC+B17uZdIWgCguESUkwFhM3n/56KxWVE3V6EokrmONQ== + dependencies: + "@types/mdx" "^2.0.0" + "@mdx-js/util@1.6.22": version "1.6.22" resolved "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz" @@ -3574,6 +3578,401 @@ "@svgr/plugin-jsx" "^6.2.1" "@svgr/plugin-svgo" "^6.2.0" +"@swagger-api/apidom-ast@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ast/-/apidom-ast-0.92.0.tgz#58faf1bbc88fa161cabe40fa16bd837f3570fd28" + integrity sha512-j9vuKaYZP3mAGXUcKeWIkSToxPPCBLJcLEfjSEh14P0n6NRJp7Yg19SA+IwHdIvOAfJonuebj/lhPOMjzd6P1g== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-error" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.1.1" + stampit "^4.3.2" + unraw "^3.0.0" + +"@swagger-api/apidom-core@>=0.90.0 <1.0.0", "@swagger-api/apidom-core@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-core/-/apidom-core-0.92.0.tgz#44bb5d58f0a551ec7529617df10a23093eac2a06" + integrity sha512-PK1zlS0UCcE5dIPtSy8/+oWfXAVf7b/iM3LRaPgaFGF5b8qa6S/zmROTh10Yjug9v9Vnuq8opEhyHkGyl+WdSA== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-ast" "^0.92.0" + "@swagger-api/apidom-error" "^0.92.0" + "@types/ramda" "~0.29.6" + minim "~0.23.8" + ramda "~0.29.1" + ramda-adjunct "^4.1.1" + short-unique-id "^5.0.2" + stampit "^4.3.2" + +"@swagger-api/apidom-error@>=0.90.0 <1.0.0", "@swagger-api/apidom-error@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-error/-/apidom-error-0.92.0.tgz#a5e93e98f689cf346b9d3d12ea31e20bb67376b1" + integrity sha512-wo7xCvTpWr5Lpt/ly1L4bhZ6W7grgtAg7SK/d8FNZR85zPJXM4FPMpcRtKktfWJ/RikQJT/g5DjI33iTqB6z/w== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + +"@swagger-api/apidom-json-pointer@>=0.90.0 <1.0.0", "@swagger-api/apidom-json-pointer@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-json-pointer/-/apidom-json-pointer-0.92.0.tgz#68188d7e1ae2988b9a8c0107e7201b9545a77764" + integrity sha512-VmZ1EXE7BWX+ndeeh9t1uFRql5jbPRmAcglUfdtu3jlg6fOqXzzgx9qFpRz9GhpMHWEGFm1ymd8tMAa1CvgcHw== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-error" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.0.0" + +"@swagger-api/apidom-ns-api-design-systems@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-api-design-systems/-/apidom-ns-api-design-systems-0.92.0.tgz#b99dc79b96a9b444e20ccb45aec49b0aa16e8996" + integrity sha512-wXEXhw0wDQIPTUqff953h44oQZr29DcoAzZfROWlGtOLItGDDMjhfIYiRg1406mXA4N7d5d0vNi9V/HXkxItQw== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-error" "^0.92.0" + "@swagger-api/apidom-ns-openapi-3-1" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.1.1" + stampit "^4.3.2" + +"@swagger-api/apidom-ns-asyncapi-2@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-asyncapi-2/-/apidom-ns-asyncapi-2-0.92.0.tgz#872fc6ef5548bacb88b3c3550ac7350e12830331" + integrity sha512-FmJLT3GqzT4HK7Mwh54cXZ4PZt58yKVtJAKWKJ0dg2/Gim0AKJWf6t6B3Z9ZFUiKyehbqP4K7gSM7qGL0tKe2Q== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-ns-json-schema-draft-7" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.1.1" + stampit "^4.3.2" + +"@swagger-api/apidom-ns-json-schema-draft-4@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-json-schema-draft-4/-/apidom-ns-json-schema-draft-4-0.92.0.tgz#11c6fede3eef005efe8b5c9d61001d24916b7633" + integrity sha512-7s2EKjCQwRXbK4Y4AGpVkyn1AANCxOUFSHebo1h2katyVeAopV0LJmbXH5yQedTltV0k3BIjnd7hS+7dI846Pw== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-ast" "^0.92.0" + "@swagger-api/apidom-core" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.1.1" + stampit "^4.3.2" + +"@swagger-api/apidom-ns-json-schema-draft-6@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-json-schema-draft-6/-/apidom-ns-json-schema-draft-6-0.92.0.tgz#59c37e8064c72b5e88939d71b6abd6a8312a94c4" + integrity sha512-zur80x04jesXVzlU9sLZhW4giO9RfOouI7L/H8v2wUlcBvjaPBn1tIqrURw2VEHKAcJORhTRusQCR21vnFot2g== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-error" "^0.92.0" + "@swagger-api/apidom-ns-json-schema-draft-4" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.1.1" + stampit "^4.3.2" + +"@swagger-api/apidom-ns-json-schema-draft-7@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-json-schema-draft-7/-/apidom-ns-json-schema-draft-7-0.92.0.tgz#7d833b1b8b968aa16c8313a8594ed8b309758d3f" + integrity sha512-DSY7lY98XHnc0wg0V38ZmBPs5HWuRuSb6G+n5Z+qs5RRodh1x5BrTIY6M0Yk3oJVbbEoFGmF0VlTe6vHf44pbw== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-error" "^0.92.0" + "@swagger-api/apidom-ns-json-schema-draft-6" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.1.1" + stampit "^4.3.2" + +"@swagger-api/apidom-ns-openapi-2@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-openapi-2/-/apidom-ns-openapi-2-0.92.0.tgz#b61cc851f21fc14fcc58fef15a0bea0ab57b87e6" + integrity sha512-OJlSTvPzK+zqzd2xXeWkF50z08Wlpygc98eVzZjYI0Af8mz7x6R5T9BCP5p6ZlQoO9OTvk4gfv7ViWXCdamObg== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-error" "^0.92.0" + "@swagger-api/apidom-ns-json-schema-draft-4" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.1.1" + stampit "^4.3.2" + +"@swagger-api/apidom-ns-openapi-3-0@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-openapi-3-0/-/apidom-ns-openapi-3-0-0.92.0.tgz#f8e9a62cc06e758a7d3b8cc8b030c28f5457281a" + integrity sha512-VGha4RRnoeoAZBWLGy37YsBzwICM3ZFNyCk2Dwpaqfg9zFN+E6BL2CtIbkxvFkMdwaMURmDItiQsw28pF0tOgQ== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-error" "^0.92.0" + "@swagger-api/apidom-ns-json-schema-draft-4" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.1.1" + stampit "^4.3.2" + +"@swagger-api/apidom-ns-openapi-3-1@>=0.90.0 <1.0.0", "@swagger-api/apidom-ns-openapi-3-1@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-openapi-3-1/-/apidom-ns-openapi-3-1-0.92.0.tgz#3a393c9c56672471233198079a1e15354629dfdd" + integrity sha512-xZD+JxifYhDoTjn76K2ZT3xNoXBQChaKfSkJr4l5Xh9Guuk0IcsPTUDRpuytuZZXVez0O401XFoUso/mZRTjkA== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-ast" "^0.92.0" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-ns-openapi-3-0" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.1.1" + stampit "^4.3.2" + +"@swagger-api/apidom-ns-workflows-1@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-ns-workflows-1/-/apidom-ns-workflows-1-0.92.0.tgz#8ee3d51bd0014fcf8dfc0b58ba03d97b8427b9c3" + integrity sha512-gl1dF+SrRHK4lLiwaK4PMjL9A5z28cW9xiMWCxRyppX/I2bVTVVOfgdAyqLWsFA0gopmITWesJxohRumG35fTw== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-ns-openapi-3-1" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.1.1" + stampit "^4.3.2" + +"@swagger-api/apidom-parser-adapter-api-design-systems-json@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-api-design-systems-json/-/apidom-parser-adapter-api-design-systems-json-0.92.0.tgz#9437cae4c06dc8933345830ff1d055eaea314cda" + integrity sha512-i07FeLdNobWzHT9LnfsdOix+XrlZN/KnQL1RODPzxWk7i7ya2e4uc3JemyHh4Tnv04G8JV32SQqtzOtMteJsdA== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-ns-api-design-systems" "^0.92.0" + "@swagger-api/apidom-parser-adapter-json" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.0.0" + +"@swagger-api/apidom-parser-adapter-api-design-systems-yaml@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-api-design-systems-yaml/-/apidom-parser-adapter-api-design-systems-yaml-0.92.0.tgz#72d97d3cef6d30c30a7de61dbdd67321b1913d59" + integrity sha512-bbjFkU0D4zqaZnd8/m1Kyx2UuHpri8ZxLdT1TiXqHweSfRQcNt4VYt0bjWBnnGGBMkHElgYbX5ov6kHvPf3wJg== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-ns-api-design-systems" "^0.92.0" + "@swagger-api/apidom-parser-adapter-yaml-1-2" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.0.0" + +"@swagger-api/apidom-parser-adapter-asyncapi-json-2@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-asyncapi-json-2/-/apidom-parser-adapter-asyncapi-json-2-0.92.0.tgz#4996bc69e9f7e17a9f4d1b8316429d5373043918" + integrity sha512-Q7gudmGA5TUGbbr0QYNQkndktP91C0WE7uDDS2IwCBtHroRDiMPFCjzE9dsjIST5WnP+LUXmxG1Bv0NLTWcSUg== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-ns-asyncapi-2" "^0.92.0" + "@swagger-api/apidom-parser-adapter-json" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.0.0" + +"@swagger-api/apidom-parser-adapter-asyncapi-yaml-2@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-asyncapi-yaml-2/-/apidom-parser-adapter-asyncapi-yaml-2-0.92.0.tgz#29eef57f3632570cdd4d8e8ba0b22fc8e046c44c" + integrity sha512-V5/VdDj0aeOKp+3AtvPSz2b0HosJfYkHPjNvPU5eafLSzqzMIR/evYq5BvKWoJL1IvLdjoEPqDVVaEZluHZTew== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-ns-asyncapi-2" "^0.92.0" + "@swagger-api/apidom-parser-adapter-yaml-1-2" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.0.0" + +"@swagger-api/apidom-parser-adapter-json@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-json/-/apidom-parser-adapter-json-0.92.0.tgz#52af0254d3c27f601d6bee5af7f6e78c2b15f939" + integrity sha512-KA1Nn6FN0zTA5JhRazwYN9voTDlmExID7Jwz6GXmY826OXqeT4Yl0Egyo1aLYrfT0S73vhC4LVqpdORWLGdZtg== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-ast" "^0.92.0" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-error" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.1.1" + tree-sitter "=0.20.4" + tree-sitter-json "=0.20.1" + web-tree-sitter "=0.20.3" + +"@swagger-api/apidom-parser-adapter-openapi-json-2@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-openapi-json-2/-/apidom-parser-adapter-openapi-json-2-0.92.0.tgz#ccaac1c6129f284aad40d6ff75a2559cbd3bcd73" + integrity sha512-8OlvjcvI/GuOFJJxN+Mc4tJSo9UWuJdzQtQOtO4k3QwWwS28hGvRTjQ5PpsXAVZoLJMAbDuRdREYD9qeIKvM2g== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-ns-openapi-2" "^0.92.0" + "@swagger-api/apidom-parser-adapter-json" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.0.0" + +"@swagger-api/apidom-parser-adapter-openapi-json-3-0@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-openapi-json-3-0/-/apidom-parser-adapter-openapi-json-3-0-0.92.0.tgz#7115ba14ee1fd303ae0d40f6ee813c14bcd69819" + integrity sha512-kzE4COaNobKIUjGsdqqXgO/LruaQHs2kTzOzHPUTR1TH1ZlB2t8MTV+6LJzGNG3IB3QSfZDd7KBEYWklsCTyTA== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-ns-openapi-3-0" "^0.92.0" + "@swagger-api/apidom-parser-adapter-json" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.0.0" + +"@swagger-api/apidom-parser-adapter-openapi-json-3-1@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-openapi-json-3-1/-/apidom-parser-adapter-openapi-json-3-1-0.92.0.tgz#f72ef7ddd55bd692d856e056795ee338ce0769e4" + integrity sha512-4gkIXfKGwEKZQ6+kxp4EdFBlAc7Kjq8GAgaC7ilGTSSxIaz5hBHBOJoe3cXWpQ/WlXiOyNCy7WdbuKRpUDKIdg== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-ns-openapi-3-1" "^0.92.0" + "@swagger-api/apidom-parser-adapter-json" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.0.0" + +"@swagger-api/apidom-parser-adapter-openapi-yaml-2@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-openapi-yaml-2/-/apidom-parser-adapter-openapi-yaml-2-0.92.0.tgz#66449fcfc680ccd59c9d1023f407529b27f7e247" + integrity sha512-TIY9cytYhA3yUf+5PcwsH9UjzKy5V4nGUtK6n5RvcL4btaGQA2LUB5CiV/1nSvYLNjYjGxhtB3haZDbHe3/gyw== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-ns-openapi-2" "^0.92.0" + "@swagger-api/apidom-parser-adapter-yaml-1-2" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.0.0" + +"@swagger-api/apidom-parser-adapter-openapi-yaml-3-0@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-openapi-yaml-3-0/-/apidom-parser-adapter-openapi-yaml-3-0-0.92.0.tgz#233ea2e347943c98cb0961ed025f16f6fe8f40f4" + integrity sha512-AUwtAxeautYtiwifNCmv6Kjs7ksptRFxcQ3sgLv2bP3f9t5jzcI9NhmgJNdbRfohHYaHMwTuUESrfsTdBgKlAA== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-ns-openapi-3-0" "^0.92.0" + "@swagger-api/apidom-parser-adapter-yaml-1-2" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.0.0" + +"@swagger-api/apidom-parser-adapter-openapi-yaml-3-1@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-openapi-yaml-3-1/-/apidom-parser-adapter-openapi-yaml-3-1-0.92.0.tgz#96a4a4f3baeaf2349043ba8bb2b4b5a22717a26b" + integrity sha512-gMR4zUZ/RrjVJVr6DnqwsCsnlplGXJk6O9UKbkoBsiom81dkcHx68BmWA2oM2lYVGKx+G8WVmVDo2EJaZvZYGg== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-ns-openapi-3-1" "^0.92.0" + "@swagger-api/apidom-parser-adapter-yaml-1-2" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.0.0" + +"@swagger-api/apidom-parser-adapter-workflows-json-1@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-workflows-json-1/-/apidom-parser-adapter-workflows-json-1-0.92.0.tgz#e31454a5b5a6ec38281a8aa4aeaf430b8fd61db7" + integrity sha512-tyLiSxEKeU6mhClFjNxrTQJA2aSgfEF7LJ/ZcJgvREsvyk6ns3op9wN2SXw4UmD+657IgN0aUPihh92aEXKovA== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-ns-workflows-1" "^0.92.0" + "@swagger-api/apidom-parser-adapter-json" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.0.0" + +"@swagger-api/apidom-parser-adapter-workflows-yaml-1@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-workflows-yaml-1/-/apidom-parser-adapter-workflows-yaml-1-0.92.0.tgz#c4bde8ebf67f1a7bde3998145830dfa6b81ce245" + integrity sha512-0Nr+5oAocuw3SZXcO8WEqnU7GGWP7O6GrsFafD6KLBL05v3I0erPfmnWQjWh6jBeXv8r5W69WEQItzES0DBJjA== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-ns-workflows-1" "^0.92.0" + "@swagger-api/apidom-parser-adapter-yaml-1-2" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.0.0" + +"@swagger-api/apidom-parser-adapter-yaml-1-2@^0.92.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-parser-adapter-yaml-1-2/-/apidom-parser-adapter-yaml-1-2-0.92.0.tgz#52cf595aa07289a4eadd1850e58d796e0ff0c59e" + integrity sha512-cFLqlhehMuY5WRdU1780Vno6iWpjMlr7CfOOloZW1rKf2lvojn0c4eDsyfWFaB2DgE+Xd4CWl55McuaPZMngsw== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-ast" "^0.92.0" + "@swagger-api/apidom-core" "^0.92.0" + "@swagger-api/apidom-error" "^0.92.0" + "@types/ramda" "~0.29.6" + ramda "~0.29.1" + ramda-adjunct "^4.1.1" + tree-sitter "=0.20.4" + tree-sitter-yaml "=0.5.0" + web-tree-sitter "=0.20.3" + +"@swagger-api/apidom-reference@>=0.90.0 <1.0.0": + version "0.92.0" + resolved "https://registry.yarnpkg.com/@swagger-api/apidom-reference/-/apidom-reference-0.92.0.tgz#11054a13e438bf15736200c6826cae845c12e465" + integrity sha512-G/qJBTpXCdwPsc5dqPjX+vAfhvtnhIFqnKtEZ71wnEvF7TpIxdeZKKfqpg+Zxi7MSuZD/Gpkr4J/eP0lO0fAdA== + dependencies: + "@babel/runtime-corejs3" "^7.20.7" + "@swagger-api/apidom-core" "^0.92.0" + "@types/ramda" "~0.29.6" + axios "^1.4.0" + minimatch "^7.4.3" + process "^0.11.10" + ramda "~0.29.1" + ramda-adjunct "^4.1.1" + stampit "^4.3.2" + optionalDependencies: + "@swagger-api/apidom-error" "^0.92.0" + "@swagger-api/apidom-json-pointer" "^0.92.0" + "@swagger-api/apidom-ns-asyncapi-2" "^0.92.0" + "@swagger-api/apidom-ns-openapi-2" "^0.92.0" + "@swagger-api/apidom-ns-openapi-3-0" "^0.92.0" + "@swagger-api/apidom-ns-openapi-3-1" "^0.92.0" + "@swagger-api/apidom-ns-workflows-1" "^0.92.0" + "@swagger-api/apidom-parser-adapter-api-design-systems-json" "^0.92.0" + "@swagger-api/apidom-parser-adapter-api-design-systems-yaml" "^0.92.0" + "@swagger-api/apidom-parser-adapter-asyncapi-json-2" "^0.92.0" + "@swagger-api/apidom-parser-adapter-asyncapi-yaml-2" "^0.92.0" + "@swagger-api/apidom-parser-adapter-json" "^0.92.0" + "@swagger-api/apidom-parser-adapter-openapi-json-2" "^0.92.0" + "@swagger-api/apidom-parser-adapter-openapi-json-3-0" "^0.92.0" + "@swagger-api/apidom-parser-adapter-openapi-json-3-1" "^0.92.0" + "@swagger-api/apidom-parser-adapter-openapi-yaml-2" "^0.92.0" + "@swagger-api/apidom-parser-adapter-openapi-yaml-3-0" "^0.92.0" + "@swagger-api/apidom-parser-adapter-openapi-yaml-3-1" "^0.92.0" + "@swagger-api/apidom-parser-adapter-workflows-json-1" "^0.92.0" + "@swagger-api/apidom-parser-adapter-workflows-yaml-1" "^0.92.0" + "@swagger-api/apidom-parser-adapter-yaml-1-2" "^0.92.0" + "@szmarczak/http-timer@^1.1.2": version "1.1.2" resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz" @@ -3586,10 +3985,10 @@ resolved "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz" integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== -"@tsconfig/docusaurus@^1.0.6": - version "1.0.7" - resolved "https://registry.yarnpkg.com/@tsconfig/docusaurus/-/docusaurus-1.0.7.tgz#a3ee3c8109b3fec091e3d61a61834e563aeee3c3" - integrity sha512-ffTXxGIP/IRMCjuzHd6M4/HdIrw1bMfC7Bv8hMkTadnePkpe0lG0oDSdbRpSDZb2rQMAgpbWiR10BvxvNYwYrg== +"@tsconfig/docusaurus@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@tsconfig/docusaurus/-/docusaurus-2.0.2.tgz#f96c7453ce9969ef938284eac74441e2d646efd7" + integrity sha512-12HWfYmgUl4M2o76/TFufGtI68wl2k/b8qPrIrG7ci9YJLrpAtadpy897Bz5v29Mlkr7a1Hq4KHdQTKtU+2rhQ== "@types/body-parser@*": version "1.19.2" @@ -3678,14 +4077,6 @@ resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.11.tgz#56588b17ae8f50c53983a524fc3cc47437969d64" integrity sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA== -"@types/hoist-non-react-statics@^3.3.0": - version "3.3.1" - resolved "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz" - integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== - dependencies: - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - "@types/html-minifier-terser@^6.0.0": version "6.0.0" resolved "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.0.0.tgz" @@ -3729,6 +4120,11 @@ dependencies: "@types/unist" "*" +"@types/mdx@^2.0.0": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@types/mdx/-/mdx-2.0.10.tgz#0d7b57fb1d83e27656156e4ee0dfba96532930e4" + integrity sha512-Rllzc5KHk0Al5/WANwgSPl1/CwjqCy+AZrGd78zuK+jO9aDM6ffblZ+zIjgPNAaEBmlO0RYDvLNh7wD0zKVgEg== + "@types/mime@*": version "3.0.1" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.1.tgz#5f8f2bca0a5863cb69bc0b0acd88c96cb1d4ae10" @@ -3774,21 +4170,18 @@ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== +"@types/ramda@~0.29.6": + version "0.29.9" + resolved "https://registry.yarnpkg.com/@types/ramda/-/ramda-0.29.9.tgz#a4c1a9d056249268ffe16c2f6d198e42c2fc994a" + integrity sha512-X3yEG6tQCWBcUAql+RPC/O1Hm9BSU+MXu2wJnCETuAgUlrEDwTA1kIOdEEE4YXDtf0zfQLHa9CCE7WYp9kqPIQ== + dependencies: + types-ramda "^0.29.6" + "@types/range-parser@*": version "1.2.4" resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== -"@types/react-redux@^7.1.20": - version "7.1.20" - resolved "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.20.tgz" - integrity sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw== - dependencies: - "@types/hoist-non-react-statics" "^3.3.0" - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - redux "^4.0.0" - "@types/react-router-config@*": version "5.0.3" resolved "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.3.tgz" @@ -3894,6 +4287,11 @@ resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz" integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== +"@types/use-sync-external-store@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43" + integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA== + "@types/ws@^8.5.1": version "8.5.4" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.4.tgz#bb10e36116d6e570dd943735f86c933c1587b8a5" @@ -4044,6 +4442,11 @@ resolved "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== +"@yarnpkg/lockfile@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" @@ -4311,6 +4714,11 @@ async-validator@^4.0.2: resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-4.0.7.tgz#034a0fd2103a6b2ebf010da75183bec299247afe" integrity sha512-Pj2IR7u8hmUEDOwB++su6baaRi+QvsgajuFB9j95foM1N2gy5HM4z60hfusIO0fBPG5uLAEl6yCJr1jNSVugEQ== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + at-least-node@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz" @@ -4342,6 +4750,15 @@ axios@^0.25.0: dependencies: follow-redirects "^1.14.7" +axios@^1.4.0: + version "1.6.5" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.5.tgz#2c090da14aeeab3770ad30c3a1461bc970fb0cd8" + integrity sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg== + dependencies: + follow-redirects "^1.15.4" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + babel-loader@^8.2.5: version "8.3.0" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.3.0.tgz#124936e841ba4fe8176786d6ff28add1f134d6a8" @@ -4487,6 +4904,15 @@ binary-extensions@^2.0.0: resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== +bl@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + body-parser@1.20.1: version "1.20.1" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" @@ -4556,6 +4982,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^3.0.1, braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" @@ -4573,16 +5006,19 @@ browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.17.5, browserslist@^4 node-releases "^2.0.8" update-browserslist-db "^1.0.10" -btoa@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz" - integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g== - buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + buffer@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -4622,6 +5058,15 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-bind@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== + dependencies: + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" @@ -4757,6 +5202,11 @@ chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + chrome-trace-event@^1.0.2: version "1.0.3" resolved "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz" @@ -4772,10 +5222,15 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== -classnames@2.x, classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" - integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== +ci-info@^3.7.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +classnames@2.x, classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1, classnames@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" + integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== clean-css@^5.1.5: version "5.2.2" @@ -4838,16 +5293,16 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" -clsx@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz" - integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== - clsx@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== +clsx@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.0.tgz#e851283bcb5c80ee7608db18487433f7b23f77cb" + integrity sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg== + coa@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz" @@ -4901,6 +5356,13 @@ combine-promises@^1.1.0: resolved "https://registry.npmjs.org/combine-promises/-/combine-promises-1.1.0.tgz" integrity sha512-ZI9jvcLDxqwaXEixOhArm3r7ReIivsXkpbyEWyeOhzz1QS0iSgBPnWvEqvIQtYyamGCYA88gFhmUrs9hrrQ0pg== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + comma-separated-tokens@^1.0.0: version "1.0.8" resolved "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz" @@ -5017,10 +5479,10 @@ cookie@0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== -cookie@~0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz" - integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== +cookie@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== copy-anything@^2.0.1: version "2.0.6" @@ -5034,13 +5496,20 @@ copy-text-to-clipboard@^3.0.1: resolved "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.0.1.tgz" integrity sha512-rvVsHrpFcL4F2P8ihsoLdFHmd404+CMg71S756oRSeQgqk51U3kicGdnvfkrxva0xXH92SjGS62B0XIJsbh+9Q== -copy-to-clipboard@^3, copy-to-clipboard@^3.2.0: +copy-to-clipboard@^3.2.0: version "3.3.1" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== dependencies: toggle-selection "^1.0.6" +copy-to-clipboard@^3.3.1: + version "3.3.3" + resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0" + integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA== + dependencies: + toggle-selection "^1.0.6" + copy-webpack-plugin@^11.0.0: version "11.0.0" resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz#96d4dbdb5f73d02dd72d0528d1958721ab72e04a" @@ -5068,15 +5537,10 @@ core-js-compat@^3.25.1: dependencies: browserslist "^4.21.5" -core-js-pure@^3.20.2: - version "3.21.1" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.21.1.tgz#8c4d1e78839f5f46208de7230cebfb72bc3bdb51" - integrity sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ== - -core-js-pure@^3.25.1: - version "3.29.1" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.29.1.tgz#1be6ca2b8772f6b4df7fc4621743286e676c6162" - integrity sha512-4En6zYVi0i0XlXHVz/bi6l1XDjCqkKRq765NXuX+SnaIatlE96Odt5lMLjdxUiNI1v9OXI5DSLWYPlmTfkTktg== +core-js-pure@^3.30.2: + version "3.35.0" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.35.0.tgz#4660033304a050215ae82e476bd2513a419fbb34" + integrity sha512-f+eRYmkou59uh7BPcyJ8MC76DiGhspj1KMxVIcF24tzP8NA9HVa1uC7BTW2tgx7E1QVCzDzsgp7kArrzhlz8Ew== core-js@^3.23.3: version "3.29.1" @@ -5110,7 +5574,7 @@ cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: path-type "^4.0.0" yaml "^1.10.0" -cross-fetch@^3.0.4, cross-fetch@^3.1.4: +cross-fetch@^3.0.4: version "3.1.5" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== @@ -5318,14 +5782,6 @@ csstype@^3.0.2: resolved "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz" integrity sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw== -d@1, d@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/d/-/d-1.0.1.tgz" - integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== - dependencies: - es5-ext "^0.10.50" - type "^1.0.1" - date-fns@2.x: version "2.28.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" @@ -5364,7 +5820,14 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" -deep-extend@0.6.0, deep-extend@^0.6.0, deep-extend@~0.6.0: +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + +deep-extend@0.6.0, deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== @@ -5374,6 +5837,11 @@ deepmerge@^4.2.2: resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== +deepmerge@~4.3.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + default-gateway@^6.0.3: version "6.0.3" resolved "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz" @@ -5386,6 +5854,15 @@ defer-to-connect@^1.0.1: resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz" integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== +define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== + dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + define-lazy-prop@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz" @@ -5412,6 +5889,11 @@ del@^6.1.1: rimraf "^3.0.2" slash "^3.0.0" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + depd@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" @@ -5434,6 +5916,11 @@ detab@2.0.4: dependencies: repeat-string "^1.5.4" +detect-libc@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.2.tgz#8ccf2ba9315350e1241b88d0ac3b0e1fbd99605d" + integrity sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw== + detect-node@^2.0.4: version "2.1.0" resolved "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz" @@ -5546,10 +6033,10 @@ domhandler@^5.0.1, domhandler@^5.0.2, domhandler@^5.0.3: dependencies: domelementtype "^2.3.0" -dompurify@=2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.3.3.tgz" - integrity sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg== +dompurify@=3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.0.6.tgz#925ebd576d54a9531b5d76f0a5bef32548351dae" + integrity sha512-ilkD8YEnnGh1zJ240uJsW7AzE+2qpbOUYjacomn3AvJ6J4JhKGSZ2nh4wUIXPZrEPppaCLx5jFe8T89Rk8tQ7w== domutils@^1.7.0: version "1.7.0" @@ -5592,6 +6079,11 @@ dot-prop@^5.2.0: dependencies: is-obj "^2.0.0" +drange@^1.0.2: + version "1.1.1" + resolved "https://registry.yarnpkg.com/drange/-/drange-1.1.1.tgz#b2aecec2aab82fcef11dbbd7b9e32b83f8f6c0b8" + integrity sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA== + duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz" @@ -5656,7 +6148,7 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== -end-of-stream@^1.1.0: +end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -5740,42 +6232,6 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: - version "0.10.53" - resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz" - integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.3" - next-tick "~1.0.0" - -es6-iterator@^2.0.3, es6-iterator@~2.0.3: - version "2.0.3" - resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz" - integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-symbol@^3.1.1, es6-symbol@~3.1.3: - version "3.1.3" - resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz" - integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== - dependencies: - d "^1.0.1" - ext "^1.1.2" - -es6-weak-map@^2.0.3: - version "2.0.3" - resolved "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz" - integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA== - dependencies: - d "1" - es5-ext "^0.10.46" - es6-iterator "^2.0.3" - es6-symbol "^3.1.1" - escalade@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" @@ -5854,14 +6310,6 @@ eval@^0.1.8: "@types/node" "*" require-like ">= 0.1.1" -event-emitter@^0.3.5: - version "0.3.5" - resolved "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz" - integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk= - dependencies: - d "1" - es5-ext "~0.10.14" - eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" @@ -5887,6 +6335,11 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== + express@^4.17.3: version "4.18.2" resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" @@ -5924,13 +6377,6 @@ express@^4.17.3: utils-merge "1.0.1" vary "~1.1.2" -ext@^1.1.2: - version "1.6.0" - resolved "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz" - integrity sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg== - dependencies: - type "^2.5.0" - extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz" @@ -6121,6 +6567,13 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" +find-yarn-workspace-root@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" + integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== + dependencies: + micromatch "^4.0.2" + flux@^4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/flux/-/flux-4.0.2.tgz" @@ -6134,6 +6587,11 @@ follow-redirects@^1.0.0, follow-redirects@^1.14.7: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf" integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw== +follow-redirects@^1.15.4: + version "1.15.5" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020" + integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== + fork-ts-checker-webpack-plugin@^6.5.0: version "6.5.0" resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.0.tgz#0282b335fa495a97e167f69018f566ea7d2a2b5e" @@ -6153,24 +6611,20 @@ fork-ts-checker-webpack-plugin@^6.5.0: semver "^7.3.2" tapable "^1.0.0" -form-data-encoder@^1.4.3: - version "1.7.1" - resolved "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz" - integrity sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg== +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" format@^0.2.0: version "0.2.2" resolved "https://registry.npmjs.org/format/-/format-0.2.2.tgz" integrity sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs= -formdata-node@^4.0.0: - version "4.3.1" - resolved "https://registry.npmjs.org/formdata-node/-/formdata-node-4.3.1.tgz" - integrity sha512-8xKSa9et4zb+yziWsD/bI+EYjdg1z2p9EpKr+o+Yk12F/wP66bmDdvjj2ZXd2K/MJlR3HBzWnuV7f82jzHRqCA== - dependencies: - node-domexception "1.0.0" - web-streams-polyfill "4.0.0-beta.1" - forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -6186,6 +6640,11 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs-extra@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" @@ -6225,6 +6684,11 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" @@ -6248,6 +6712,16 @@ get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.1" +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== + dependencies: + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + get-own-enumerable-property-symbols@^3.0.0: version "3.0.2" resolved "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz" @@ -6285,6 +6759,11 @@ github-buttons@^2.8.0: resolved "https://registry.yarnpkg.com/github-buttons/-/github-buttons-2.21.1.tgz#9e55eb83b70c9149a21c235db2e971c53d4d98a2" integrity sha512-n9bCQ8sj+5oX1YH5NeyWGbAclRDtHEhMBzqw2ctsWpdEHOwVgfruRu0VIVy01Ah10dd/iFajMHYU71L7IBWBOw== +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== + github-slugger@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/github-slugger/-/github-slugger-1.4.0.tgz" @@ -6384,6 +6863,13 @@ globby@^13.1.1: merge2 "^1.4.1" slash "^4.0.0" +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + got@^9.6.0: version "9.6.0" resolved "https://registry.npmjs.org/got/-/got-9.6.0.tgz" @@ -6401,6 +6887,11 @@ got@^9.6.0: to-readable-stream "^1.0.0" url-parse-lax "^3.0.0" +graceful-fs@^4.1.11: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.9" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" @@ -6443,6 +6934,18 @@ has-flag@^4.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" + integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== + dependencies: + get-intrinsic "^1.2.2" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + has-symbols@^1.0.1, has-symbols@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz" @@ -6472,6 +6975,13 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + hast-to-hyperscript@^9.0.0: version "9.0.1" resolved "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz" @@ -6562,7 +7072,7 @@ history@^4.9.0: tiny-warning "^1.0.0" value-equal "^1.0.1" -hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0: version "3.3.2" resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -6731,7 +7241,7 @@ icss-utils@^5.0.0, icss-utils@^5.1.0: resolved "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz" integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== -ieee754@^1.2.1: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -6804,7 +7314,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -6948,14 +7458,6 @@ is-docker@^2.0.0, is-docker@^2.1.1: resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== -is-dom@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/is-dom/-/is-dom-1.1.0.tgz" - integrity sha512-u82f6mvhYxRPKpw8V1N0W8ce1xXwOrQtgGcxl6UCL5zBmZu3is/18K0rR7uFCnMDuAsS/3W54mGL4vsaFUQlEQ== - dependencies: - is-object "^1.0.1" - is-window "^1.0.2" - is-extendable@^0.1.0: version "0.1.1" resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz" @@ -7023,11 +7525,6 @@ is-obj@^2.0.0: resolved "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz" integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== -is-object@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz" - integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== - is-path-cwd@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz" @@ -7055,10 +7552,10 @@ is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-promise@^2.2.2: - version "2.2.2" - resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz" - integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== is-regex@^1.1.4: version "1.1.4" @@ -7124,17 +7621,12 @@ is-whitespace-character@^1.0.0: resolved "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz" integrity sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w== -is-window@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/is-window/-/is-window-1.0.2.tgz" - integrity sha1-LIlspT25feRdPDMTOmXYyfVjSA0= - is-word-character@^1.0.0: version "1.0.4" resolved "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz" integrity sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA== -is-wsl@^2.2.0: +is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -7151,6 +7643,11 @@ isarray@0.0.1: resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" @@ -7263,6 +7760,16 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== +json-stable-stringify@^1.0.2: + version "1.1.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz#52d4361b47d49168bcc4e564189a42e5a7439454" + integrity sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg== + dependencies: + call-bind "^1.0.5" + isarray "^2.0.5" + jsonify "^0.0.1" + object-keys "^1.1.1" + json2mq@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/json2mq/-/json2mq-0.2.0.tgz#b637bd3ba9eabe122c83e9720483aeb10d2c904a" @@ -7289,6 +7796,11 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +jsonify@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" + integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== + keyv@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz" @@ -7301,6 +7813,13 @@ kind-of@^6.0.0, kind-of@^6.0.2: resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +klaw-sync@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" + integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== + dependencies: + graceful-fs "^4.1.11" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" @@ -7423,7 +7942,7 @@ lodash.uniq@4.5.0, lodash.uniq@^4.5.0: resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21: +lodash@^4.15.0, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -7474,13 +7993,6 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -lru-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz" - integrity sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM= - dependencies: - es5-ext "~0.10.2" - make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -7573,20 +8085,6 @@ memoize-one@^6.0.0: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== -memoizee@^0.4.15: - version "0.4.15" - resolved "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz" - integrity sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ== - dependencies: - d "^1.0.1" - es5-ext "^0.10.53" - es6-weak-map "^2.0.3" - event-emitter "^0.3.5" - is-promise "^2.2.2" - lru-queue "^0.1.0" - next-tick "^1.1.0" - timers-ext "^0.1.7" - merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -7645,7 +8143,7 @@ mime-types@2.1.18: dependencies: mime-db "~1.33.0" -mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -7672,6 +8170,11 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + mini-css-extract-plugin@^2.6.1: version "2.7.3" resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.3.tgz#794aa4d598bf178a66b2a35fe287c3df3eac394e" @@ -7679,6 +8182,13 @@ mini-css-extract-plugin@^2.6.1: dependencies: schema-utils "^4.0.0" +minim@~0.23.8: + version "0.23.8" + resolved "https://registry.yarnpkg.com/minim/-/minim-0.23.8.tgz#a529837afe1654f119dfb68ce7487dd8d4866b9c" + integrity sha512-bjdr2xW1dBCMsMGGsUeqM4eFI60m94+szhxWys+B1ztIt6gWSfeGBdSVCIawezeHYLYn0j6zrsXdQS/JllBzww== + dependencies: + lodash "^4.15.0" + minimalistic-assert@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" @@ -7698,11 +8208,28 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" +minimatch@^7.4.3: + version "7.4.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.4.6.tgz#845d6f254d8f4a5e4fd6baf44d5f10c8448365fb" + integrity sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.5: version "1.2.6" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== +minimist@^1.2.3, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + mkdirp@~0.5.1: version "0.5.5" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz" @@ -7738,11 +8265,21 @@ multicast-dns@^7.2.5: dns-packet "^5.2.2" thunky "^1.0.2" +nan@^2.14.0, nan@^2.17.0, nan@^2.18.0: + version "2.18.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554" + integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w== + nanoid@^3.3.6: version "3.3.6" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== +napi-build-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" + integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== + needle@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/needle/-/needle-3.2.0.tgz#07d240ebcabfd65c76c03afae7f6defe6469df44" @@ -7762,16 +8299,6 @@ neo-async@^2.6.2: resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -next-tick@1, next-tick@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz" - integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== - -next-tick@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz" - integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= - no-case@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz" @@ -7780,9 +8307,21 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" -node-domexception@1.0.0: +node-abi@^3.3.0: + version "3.54.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.54.0.tgz#f6386f7548817acac6434c6cba02999c9aebcc69" + integrity sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA== + dependencies: + semver "^7.3.5" + +node-abort-controller@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548" + integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ== + +node-domexception@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== node-emoji@^1.10.0: @@ -7792,6 +8331,14 @@ node-emoji@^1.10.0: dependencies: lodash "^4.17.21" +node-fetch-commonjs@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/node-fetch-commonjs/-/node-fetch-commonjs-3.3.2.tgz#0dd0fd4c4a314c5234f496ff7b5d9ce5a6c8feaa" + integrity sha512-VBlAiynj3VMLrotgwOS3OyECFxas5y7ltLcK4t41lMUZeaK15Ym4QRkqN0EQKAFL42q9i21EPKjzLUPfltR72A== + dependencies: + node-domexception "^1.0.0" + web-streams-polyfill "^3.0.3" + node-fetch@2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" @@ -7941,6 +8488,14 @@ onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" +open@^7.4.2: + version "7.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + open@^8.0.9, open@^8.4.0: version "8.4.0" resolved "https://registry.npmjs.org/open/-/open-8.4.0.tgz" @@ -7955,6 +8510,11 @@ opener@^1.5.2: resolved "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz" integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + p-cancelable@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz" @@ -8105,6 +8665,27 @@ pascal-case@^3.1.2: no-case "^3.0.4" tslib "^2.0.3" +patch-package@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-8.0.0.tgz#d191e2f1b6e06a4624a0116bcb88edd6714ede61" + integrity sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA== + dependencies: + "@yarnpkg/lockfile" "^1.1.0" + chalk "^4.1.2" + ci-info "^3.7.0" + cross-spawn "^7.0.3" + find-yarn-workspace-root "^2.0.0" + fs-extra "^9.0.0" + json-stable-stringify "^1.0.2" + klaw-sync "^6.0.0" + minimist "^1.2.6" + open "^7.4.2" + rimraf "^2.6.3" + semver "^7.5.3" + slash "^2.0.0" + tmp "^0.0.33" + yaml "^2.2.2" + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" @@ -8494,6 +9075,24 @@ postcss@^8.3.11, postcss@^8.4.14, postcss@^8.4.17, postcss@^8.4.7: picocolors "^1.0.0" source-map-js "^1.0.2" +prebuild-install@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45" + integrity sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw== + dependencies: + detect-libc "^2.0.0" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.3" + mkdirp-classic "^0.5.3" + napi-build-utils "^1.0.1" + node-abi "^3.3.0" + pump "^3.0.0" + rc "^1.2.7" + simple-get "^4.0.0" + tar-fs "^2.0.0" + tunnel-agent "^0.6.0" + prepend-http@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz" @@ -8522,21 +9121,26 @@ prism-react-renderer@^1.3.5: resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.3.5.tgz#786bb69aa6f73c32ba1ee813fbe17a0115435085" integrity sha512-IJ+MSwBWKG+SM3b2SUfdrhC+gu01QkV2KmRQgREThBfSQRoufqRfxfHUxpG1WcaFjP+kojcFyO9Qqtpgt3qLCg== -prismjs@^1.25.0, prismjs@~1.25.0: - version "1.25.0" - resolved "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz" - integrity sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg== - -prismjs@^1.28.0: +prismjs@^1.27.0, prismjs@^1.28.0: version "1.29.0" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.29.0.tgz#f113555a8fa9b57c35e637bba27509dcf802dd12" integrity sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q== +prismjs@~1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.27.0.tgz#bb6ee3138a0b438a3653dd4d6ce0cc6510a45057" + integrity sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA== + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + promise@^7.1.1: version "7.3.1" resolved "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz" @@ -8552,14 +9156,14 @@ prompts@^2.4.2: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.0.0, prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2: - version "15.7.2" - resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== +prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== dependencies: loose-envify "^1.4.0" object-assign "^4.1.1" - react-is "^16.8.1" + react-is "^16.13.1" property-information@^5.0.0, property-information@^5.3.0: version "5.6.0" @@ -8576,6 +9180,11 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -8589,11 +9198,6 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - punycode@^1.3.2: version "1.4.1" resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz" @@ -8621,17 +9225,19 @@ q@^1.1.2: resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= -qs@6.11.0, qs@^6.9.4: +qs@6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== dependencies: side-channel "^1.0.4" -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= +qs@^6.10.2: + version "6.11.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" + integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== + dependencies: + side-channel "^1.0.4" querystringify@^2.1.1: version "2.2.0" @@ -8650,6 +9256,24 @@ queue@6.0.2: dependencies: inherits "~2.0.3" +ramda-adjunct@^4.0.0, ramda-adjunct@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ramda-adjunct/-/ramda-adjunct-4.1.1.tgz#085ca9a7bf19857378eff648f9852b15136dc66f" + integrity sha512-BnCGsZybQZMDGram9y7RiryoRHS5uwx8YeGuUeDKuZuvK38XO6JJfmK85BwRWAKFA6pZ5nZBO/HBFtExVaf31w== + +ramda@~0.29.1: + version "0.29.1" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.29.1.tgz#408a6165b9555b7ba2fc62555804b6c5a2eca196" + integrity sha512-OfxIeWzd4xdUNxlWhgFazxsA/nl3mS4/jGZI5n00uWOoSSFRhC1b6gl6xvmzUamgmqELraWp0J/qqVlXYPDPyA== + +randexp@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.5.3.tgz#f31c2de3148b30bdeb84b7c3f59b0ebb9fec3738" + integrity sha512-U+5l2KrcMNOUPYvazA3h5ekF80FHTUG+87SEAmHZmolh1M+i/WyTCxVzmi+tidIa1tM4BSe8g2Y/D3loWDjj+w== + dependencies: + drange "^1.0.2" + ret "^0.2.0" + randombytes@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" @@ -9065,7 +9689,7 @@ rc-virtual-list@^3.2.0, rc-virtual-list@^3.4.1: rc-resize-observer "^1.0.0" rc-util "^5.0.7" -rc@^1.2.8: +rc@^1.2.7, rc@^1.2.8: version "1.2.8" resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -9085,21 +9709,21 @@ react-base16-styling@^0.6.0: lodash.flow "^3.3.0" pure-color "^1.2.0" -react-copy-to-clipboard@5.0.4: - version "5.0.4" - resolved "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.4.tgz" - integrity sha512-IeVAiNVKjSPeGax/Gmkqfa/+PuMTBhutEvFUaMQLwE2tS0EXrAdgOpWDX26bWTXF3HrioorR7lr08NqeYUWQCQ== +react-copy-to-clipboard@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz#09aae5ec4c62750ccb2e6421a58725eabc41255c" + integrity sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A== dependencies: - copy-to-clipboard "^3" - prop-types "^15.5.8" + copy-to-clipboard "^3.3.1" + prop-types "^15.8.1" -react-debounce-input@=3.2.4: - version "3.2.4" - resolved "https://registry.npmjs.org/react-debounce-input/-/react-debounce-input-3.2.4.tgz" - integrity sha512-fX70bNj0fLEYO2Zcvuh7eh9wOUQ29GIx6r8IxIJlc0i0mpUH++9ax0BhfAYfzndADli3RAMROrZQ014J01owrg== +react-debounce-input@=3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/react-debounce-input/-/react-debounce-input-3.3.0.tgz#85e3ebcaa41f2016e50613134a1ec9fe3cdb422e" + integrity sha512-VEqkvs8JvY/IIZvh71Z0TC+mdbxERvYF33RcebnodlsUZ8RSgyKe2VWaHXv4+/8aoOgXLxWrdsYs2hDhcwbUgA== dependencies: lodash.debounce "^4" - prop-types "^15.7.2" + prop-types "^15.8.1" react-dev-utils@^12.0.1: version "12.0.1" @@ -9191,25 +9815,16 @@ react-immutable-pure-component@^2.2.0: resolved "https://registry.npmjs.org/react-immutable-pure-component/-/react-immutable-pure-component-2.2.2.tgz" integrity sha512-vkgoMJUDqHZfXXnjVlG3keCxSO/U6WeDQ5/Sl0GK2cH8TOxEzQ5jXqDXHEL/jqk6fsNxV05oH5kD7VNMUE2k+A== -react-inspector@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/react-inspector/-/react-inspector-5.1.1.tgz" - integrity sha512-GURDaYzoLbW8pMGXwYPDBIv6nqei4kK7LPRZ9q9HCZF54wqXz/dnylBp/kfE9XmekBhHvLDdcYeyIwSrvtOiWg== - dependencies: - "@babel/runtime" "^7.0.0" - is-dom "^1.0.0" - prop-types "^15.0.0" +react-inspector@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-6.0.2.tgz#aa3028803550cb6dbd7344816d5c80bf39d07e9d" + integrity sha512-x+b7LxhmHXjHoU/VrFAzw5iutsILRoYyDq97EDYdFpPLcvqtEzk4ZSZSQjnFPbr5T57tLXnHcqFYoN1pI6u8uQ== -react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1: +react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react-is@^17.0.2: - version "17.0.2" - resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== - react-json-view@^1.21.3: version "1.21.3" resolved "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz" @@ -9232,17 +9847,13 @@ react-loadable-ssr-addon-v5-slorber@^1.0.1: dependencies: "@babel/runtime" "^7.10.3" -react-redux@^7.2.4: - version "7.2.6" - resolved "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz" - integrity sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ== +react-redux@^9.0.4: + version "9.1.0" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.1.0.tgz#46a46d4cfed4e534ce5452bb39ba18e1d98a8197" + integrity sha512-6qoDzIO+gbrza8h3hjMA9aq4nwVFCKFtY2iLxCtVT38Swyy2C/dJCGBXHeHLtx6qlg/8qzc2MrhOeduf5K32wQ== dependencies: - "@babel/runtime" "^7.15.4" - "@types/react-redux" "^7.1.20" - hoist-non-react-statics "^3.3.2" - loose-envify "^1.4.0" - prop-types "^15.7.2" - react-is "^17.0.2" + "@types/use-sync-external-store" "^0.0.3" + use-sync-external-store "^1.0.0" react-router-config@^5.1.1: version "5.1.1" @@ -9279,16 +9890,16 @@ react-router@5.3.4, react-router@^5.3.3: tiny-invariant "^1.0.2" tiny-warning "^1.0.0" -react-syntax-highlighter@^15.4.5: - version "15.4.5" - resolved "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.4.5.tgz" - integrity sha512-RC90KQTxZ/b7+9iE6s9nmiFLFjWswUcfULi4GwVzdFVKVMQySkJWBuOmJFfjwjMVCo0IUUuJrWebNKyviKpwLQ== +react-syntax-highlighter@^15.5.0: + version "15.5.0" + resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz#4b3eccc2325fa2ec8eff1e2d6c18fa4a9e07ab20" + integrity sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg== dependencies: "@babel/runtime" "^7.3.1" highlight.js "^10.4.1" lowlight "^1.17.0" - prismjs "^1.25.0" - refractor "^3.2.0" + prismjs "^1.27.0" + refractor "^3.6.0" react-textarea-autosize@^8.3.2: version "8.3.3" @@ -9329,6 +9940,15 @@ readable-stream@^3.0.6: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@^3.1.1, readable-stream@^3.4.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" @@ -9360,21 +9980,19 @@ redux-immutable@^4.0.0: resolved "https://registry.npmjs.org/redux-immutable/-/redux-immutable-4.0.0.tgz" integrity sha1-Ohoy32Y2ZGK2NpHw4dw15HK7yfM= -redux@^4.0.0, redux@^4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz" - integrity sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw== - dependencies: - "@babel/runtime" "^7.9.2" +redux@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b" + integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w== -refractor@^3.2.0: - version "3.5.0" - resolved "https://registry.npmjs.org/refractor/-/refractor-3.5.0.tgz" - integrity sha512-QwPJd3ferTZ4cSPPjdP5bsYHMytwWYnAN5EEnLtGvkqp/FCCnGsBgxrm9EuIDnjUC3Uc/kETtvVi7fSIVC74Dg== +refractor@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.6.0.tgz#ac318f5a0715ead790fcfb0c71f4dd83d977935a" + integrity sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA== dependencies: hastscript "^6.0.0" parse-entities "^2.0.0" - prismjs "~1.25.0" + prismjs "~1.27.0" regenerate-unicode-properties@^10.1.0: version "10.1.0" @@ -9405,6 +10023,11 @@ regenerator-runtime@^0.13.4: resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + regenerator-transform@^0.14.2: version "0.14.5" resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz" @@ -9577,10 +10200,10 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= -reselect@^4.0.0: - version "4.1.5" - resolved "https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz" - integrity sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ== +reselect@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.1.0.tgz#c479139ab9dd91be4d9c764a7f3868210ef8cd21" + integrity sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg== resize-observer-polyfill@^1.5.0, resize-observer-polyfill@^1.5.1: version "1.5.1" @@ -9621,6 +10244,11 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" +ret@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.2.2.tgz#b6861782a1f4762dce43402a71eb7a283f44573c" + integrity sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ== + retry@^0.13.1: version "0.13.1" resolved "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz" @@ -9631,6 +10259,13 @@ reusify@^1.0.4: resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + rimraf@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" @@ -9781,7 +10416,7 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8: +semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.3: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -9865,6 +10500,17 @@ serve-static@1.15.0: parseurl "~1.3.3" send "0.18.0" +set-function-length@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.0.tgz#2f81dc6c16c7059bda5ab7c82c11f03a515ed8e1" + integrity sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w== + dependencies: + define-data-property "^1.1.1" + function-bind "^1.1.2" + get-intrinsic "^1.2.2" + gopd "^1.0.1" + has-property-descriptors "^1.0.1" + setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" @@ -9926,6 +10572,11 @@ shelljs@^0.8.5: interpret "^1.0.0" rechoir "^0.6.2" +short-unique-id@^5.0.2: + version "5.0.3" + resolved "https://registry.yarnpkg.com/short-unique-id/-/short-unique-id-5.0.3.tgz#bc6975dc5e8b296960ff5ac91ddabbc7ddb693d9" + integrity sha512-yhniEILouC0s4lpH0h7rJsfylZdca10W9mDJRAFh3EpcSUanCHGb0R7kcFOIUCZYSAPo0PUD5ZxWQdW0T4xaug== + side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -9940,6 +10591,20 @@ signal-exit@^3.0.2, signal-exit@^3.0.3: resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz" integrity sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ== +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543" + integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA== + dependencies: + decompress-response "^6.0.0" + once "^1.3.1" + simple-concat "^1.0.0" + sirv@^1.0.7: version "1.0.18" resolved "https://registry.npmjs.org/sirv/-/sirv-1.0.18.tgz" @@ -9964,6 +10629,11 @@ sitemap@^7.1.1: arg "^5.0.0" sax "^1.2.4" +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + slash@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" @@ -10049,6 +10719,11 @@ stable@^0.1.8: resolved "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== +stampit@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/stampit/-/stampit-4.3.2.tgz#cfd3f607dd628a161ce6305621597994b4d56573" + integrity sha512-pE2org1+ZWQBnIxRPrBM2gVupkuDD0TTNIo1H6GdT/vO82NXli2z8lRE8cu/nBIHrcOCXFBAHpb9ZldrB2/qOA== + state-toggle@^1.0.0: version "1.0.3" resolved "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz" @@ -10250,60 +10925,64 @@ svgo@^2.5.0, svgo@^2.7.0: picocolors "^1.0.0" stable "^0.1.8" -swagger-client@^3.17.0: - version "3.17.0" - resolved "https://registry.npmjs.org/swagger-client/-/swagger-client-3.17.0.tgz" - integrity sha512-d8DOEME49wTXm+uT+lBAjJ5D6IDjEHdbkqa7MbcslR2c+oHIhi13ObwleVWGfr89MPkWgBl6RBq9VUHmrBJRbg== - dependencies: - "@babel/runtime-corejs3" "^7.11.2" - btoa "^1.2.1" - cookie "~0.4.1" - cross-fetch "^3.1.4" - deep-extend "~0.6.0" +swagger-client@^3.25.0: + version "3.25.0" + resolved "https://registry.yarnpkg.com/swagger-client/-/swagger-client-3.25.0.tgz#c59b181bed7172475d275487e6ab8365bd3f06ec" + integrity sha512-p143zWkIhgyh2E5+3HPFMlCw3WkV9RbX9HyftfBdiccCbOlmHdcJC0XEJZxcm+ZA+80DORs0F30/mzk7sx4iwA== + dependencies: + "@babel/runtime-corejs3" "^7.22.15" + "@swagger-api/apidom-core" ">=0.90.0 <1.0.0" + "@swagger-api/apidom-error" ">=0.90.0 <1.0.0" + "@swagger-api/apidom-json-pointer" ">=0.90.0 <1.0.0" + "@swagger-api/apidom-ns-openapi-3-1" ">=0.90.0 <1.0.0" + "@swagger-api/apidom-reference" ">=0.90.0 <1.0.0" + cookie "~0.6.0" + deepmerge "~4.3.0" fast-json-patch "^3.0.0-1" - form-data-encoder "^1.4.3" - formdata-node "^4.0.0" + is-plain-object "^5.0.0" js-yaml "^4.1.0" - lodash "^4.17.21" - qs "^6.9.4" + node-abort-controller "^3.1.1" + node-fetch-commonjs "^3.3.1" + qs "^6.10.2" traverse "~0.6.6" - url "~0.11.0" + undici "^5.24.0" -swagger-ui-react@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/swagger-ui-react/-/swagger-ui-react-4.1.3.tgz#a722ecbe54ef237fa9080447a7c708c4c72d846a" - integrity sha512-o1AoXUTNH40cxWus0QOeWQ8x9tSIEmrLBrOgAOHDnvWJ1qyjT8PjgHjPbUVjMbja18coyuaAAeUdyLKvLGmlDA== +swagger-ui-react@^5.11.0: + version "5.11.0" + resolved "https://registry.yarnpkg.com/swagger-ui-react/-/swagger-ui-react-5.11.0.tgz#ed50f61ce7aa2c322b3a2435f2aa38396668431d" + integrity sha512-iqc5/Z8nvqOdjU2LuWYbREnDmKj5gndZSESTH9dXfymlzLc2NoPQmXZAw02U8kFgHyciX0yDMp3oaCw1zBdPSA== dependencies: - "@babel/runtime-corejs3" "^7.16.3" - "@braintree/sanitize-url" "^5.0.2" + "@babel/runtime-corejs3" "^7.23.7" + "@braintree/sanitize-url" "=7.0.0" base64-js "^1.5.1" - classnames "^2.3.1" + classnames "^2.5.1" css.escape "1.5.1" deep-extend "0.6.0" - dompurify "=2.3.3" + dompurify "=3.0.6" ieee754 "^1.2.1" immutable "^3.x.x" js-file-download "^0.4.12" js-yaml "=4.1.0" lodash "^4.17.21" - memoizee "^0.4.15" - prop-types "^15.7.2" + patch-package "^8.0.0" + prop-types "^15.8.1" + randexp "^0.5.3" randombytes "^2.1.0" - react-copy-to-clipboard "5.0.4" - react-debounce-input "=3.2.4" + react-copy-to-clipboard "5.1.0" + react-debounce-input "=3.3.0" react-immutable-proptypes "2.2.0" react-immutable-pure-component "^2.2.0" - react-inspector "^5.1.1" - react-redux "^7.2.4" - react-syntax-highlighter "^15.4.5" - redux "^4.1.2" + react-inspector "^6.0.1" + react-redux "^9.0.4" + react-syntax-highlighter "^15.5.0" + redux "^5.0.0" redux-immutable "^4.0.0" remarkable "^2.0.1" - reselect "^4.0.0" + reselect "^5.0.1" serialize-error "^8.1.0" sha.js "^2.4.11" - swagger-client "^3.17.0" - url-parse "^1.5.3" + swagger-client "^3.25.0" + url-parse "^1.5.10" xml "=1.0.1" xml-but-prettier "^1.0.1" zenscroll "^4.0.2" @@ -10318,6 +10997,27 @@ tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== +tar-fs@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + +tar-stream@^2.1.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.3.3: version "5.3.7" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz#ef760632d24991760f339fe9290deb936ad1ffc7" @@ -10359,14 +11059,6 @@ thunky@^1.0.2: resolved "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz" integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== -timers-ext@^0.1.7: - version "0.1.7" - resolved "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz" - integrity sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ== - dependencies: - es5-ext "~0.10.46" - next-tick "1" - tiny-invariant@^1.0.2: version "1.2.0" resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz" @@ -10377,6 +11069,13 @@ tiny-warning@^1.0.0: resolved "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" @@ -10419,6 +11118,28 @@ traverse@~0.6.6: resolved "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz" integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc= +tree-sitter-json@=0.20.1: + version "0.20.1" + resolved "https://registry.yarnpkg.com/tree-sitter-json/-/tree-sitter-json-0.20.1.tgz#d1fe6c59571dd3a987ebb3f5aeef404f37b3a453" + integrity sha512-482hf7J+aBwhksSw8yWaqI8nyP1DrSwnS4IMBShsnkFWD3SE8oalHnsEik59fEVi3orcTCUtMzSjZx+0Tpa6Vw== + dependencies: + nan "^2.18.0" + +tree-sitter-yaml@=0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/tree-sitter-yaml/-/tree-sitter-yaml-0.5.0.tgz#c617ba72837399d8105ec10cdb4c360e1ed76076" + integrity sha512-POJ4ZNXXSWIG/W4Rjuyg36MkUD4d769YRUGKRqN+sVaj/VCo6Dh6Pkssn1Rtewd5kybx+jT1BWMyWN0CijXnMA== + dependencies: + nan "^2.14.0" + +tree-sitter@=0.20.4: + version "0.20.4" + resolved "https://registry.yarnpkg.com/tree-sitter/-/tree-sitter-0.20.4.tgz#7d9d4f769fc05342ef43e5559f7ff34b0fc48327" + integrity sha512-rjfR5dc4knG3jnJNN/giJ9WOoN1zL/kZyrS0ILh+eqq8RNcIbiXA63JsMEgluug0aNvfQvK4BfCErN1vIzvKog== + dependencies: + nan "^2.17.0" + prebuild-install "^7.1.1" + trim-trailing-lines@^1.0.0: version "1.1.4" resolved "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz" @@ -10439,6 +11160,11 @@ ts-essentials@^2.0.3: resolved "https://registry.npmjs.org/ts-essentials/-/ts-essentials-2.0.12.tgz" integrity sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w== +ts-toolbelt@^9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz#50a25426cfed500d4a09bd1b3afb6f28879edfd5" + integrity sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w== + tslib@^1.9.3: version "1.14.1" resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" @@ -10449,6 +11175,13 @@ tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" + type-fest@^0.20.2: version "0.20.2" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" @@ -10467,16 +11200,6 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -type@^1.0.1: - version "1.2.0" - resolved "https://registry.npmjs.org/type/-/type-1.2.0.tgz" - integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== - -type@^2.5.0: - version "2.5.0" - resolved "https://registry.npmjs.org/type/-/type-2.5.0.tgz" - integrity sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw== - typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz" @@ -10484,10 +11207,17 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typescript@^4.3.5: - version "4.4.4" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz" - integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== +types-ramda@^0.29.6: + version "0.29.6" + resolved "https://registry.yarnpkg.com/types-ramda/-/types-ramda-0.29.6.tgz#a1d2a3c15a48e27d35832d7194d93369975f1427" + integrity sha512-VJoOk1uYNh9ZguGd3eZvqkdhD4hTGtnjRBUx5Zc0U9ftmnCgiWcSj/lsahzKunbiwRje1MxxNkEy1UdcXRCpYw== + dependencies: + ts-toolbelt "^9.6.0" + +typescript@^5.3.3: + version "5.3.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37" + integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== ua-parser-js@^0.7.30: version "0.7.33" @@ -10504,6 +11234,13 @@ unbox-primitive@^1.0.1: has-symbols "^1.0.2" which-boxed-primitive "^1.0.2" +undici@^5.24.0: + version "5.28.2" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.2.tgz#fea200eac65fc7ecaff80a023d1a0543423b4c91" + integrity sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w== + dependencies: + "@fastify/busboy" "^2.0.0" + unherit@^1.0.4: version "1.1.3" resolved "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz" @@ -10644,6 +11381,11 @@ unquote@~1.1.1: resolved "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz" integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= +unraw@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unraw/-/unraw-3.0.0.tgz#73443ed70d2ab09ccbac2b00525602d5991fbbe3" + integrity sha512-08/DA66UF65OlpUDIQtbJyrqTR0jTAlJ+jsnkQ4jxR7+K5g5YG1APZKQSMCE1vqqmD+2pv6+IdEjmopFatacvg== + update-browserslist-db@^1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" @@ -10695,7 +11437,7 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" -url-parse@^1.5.3: +url-parse@^1.5.10: version "1.5.10" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== @@ -10703,14 +11445,6 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" -url@~0.11.0: - version "0.11.0" - resolved "https://registry.npmjs.org/url/-/url-0.11.0.tgz" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - use-composed-ref@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.1.0.tgz" @@ -10730,7 +11464,7 @@ use-latest@^1.0.0: dependencies: use-isomorphic-layout-effect "^1.0.0" -use-sync-external-store@^1.2.0: +use-sync-external-store@^1.0.0, use-sync-external-store@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== @@ -10834,10 +11568,15 @@ web-namespaces@^1.0.0: resolved "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz" integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw== -web-streams-polyfill@4.0.0-beta.1: - version "4.0.0-beta.1" - resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.1.tgz" - integrity sha512-3ux37gEX670UUphBF9AMCq8XM6iQ8Ac6A+DSRRjDoRBm1ufCkaCDdNVbaqq60PsEkdNlLKrGtv/YBP4EJXqNtQ== +web-streams-polyfill@^3.0.3: + version "3.3.2" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.3.2.tgz#32e26522e05128203a7de59519be3c648004343b" + integrity sha512-3pRGuxRF5gpuZc0W+EpwQRmCD7gRqcDOMt688KmdlDAgAyaB1XlN0zq2njfDNm44XVdIouE7pZ6GzbdyH47uIQ== + +web-tree-sitter@=0.20.3: + version "0.20.3" + resolved "https://registry.yarnpkg.com/web-tree-sitter/-/web-tree-sitter-0.20.3.tgz#3dd17b283ad63b1d8c07c5ea814f0fefb2b1f776" + integrity sha512-zKGJW9r23y3BcJusbgvnOH2OYAW40MXAOi9bi3Gcc7T4Gms9WWgXF8m6adsJWpGJEhgOzCrfiz1IzKowJWrtYw== webidl-conversions@^3.0.0: version "3.0.1" @@ -11141,6 +11880,11 @@ yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yaml@^2.2.2: + version "2.3.4" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" + integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" diff --git a/scripts/benchmark_migration.py b/scripts/benchmark_migration.py index 466fab6f130e6..90d94853dccb8 100644 --- a/scripts/benchmark_migration.py +++ b/scripts/benchmark_migration.py @@ -142,8 +142,6 @@ def main( filepath: str, limit: int = 1000, force: bool = False, no_auto_cleanup: bool = False ) -> None: auto_cleanup = not no_auto_cleanup - session = db.session() - print(f"Importing migration script: {filepath}") module = import_migration_script(Path(filepath)) @@ -174,10 +172,9 @@ def main( models = find_models(module) model_rows: dict[type[Model], int] = {} for model in models: - rows = session.query(model).count() + rows = db.session.query(model).count() print(f"- {model.__name__} ({rows} rows in table {model.__tablename__})") model_rows[model] = rows - session.close() print("Benchmarking migration") results: dict[str, float] = {} @@ -199,16 +196,16 @@ def main( print(f"- Adding {missing} entities to the {model.__name__} model") bar = ChargingBar("Processing", max=missing) try: - for entity in add_sample_rows(session, model, missing): + for entity in add_sample_rows(model, missing): entities.append(entity) bar.next() except Exception: - session.rollback() + db.session.rollback() raise bar.finish() model_rows[model] = min_entities - session.add_all(entities) - session.commit() + db.session.add_all(entities) + db.session.commit() if auto_cleanup: new_models[model].extend(entities) @@ -227,10 +224,10 @@ def main( print("Cleaning up DB") # delete in reverse order of creation to handle relationships for model, entities in list(new_models.items())[::-1]: - session.query(model).filter( + db.session.query(model).filter( model.id.in_(entity.id for entity in entities) ).delete(synchronize_session=False) - session.commit() + db.session.commit() if current_revision != revision and not force: click.confirm(f"\nRevert DB to {revision}?", abort=True) diff --git a/superset-embedded-sdk/README.md b/superset-embedded-sdk/README.md index 7e05d94a6ce1d..94c759a528d94 100644 --- a/superset-embedded-sdk/README.md +++ b/superset-embedded-sdk/README.md @@ -76,6 +76,10 @@ Guest tokens can have Row Level Security rules which filter data for the user ca The agent making the `POST` request must be authenticated with the `can_grant_guest_token` permission. +Within your app, using the Guest Token will then allow authentication to your Superset instance via creating an Anonymous user object. This guest anonymous user will default to the public role as per this setting `GUEST_ROLE_NAME = "Public"`. ++ ++The user parameters in the example below are optional and are provided as a means of passing user attributes that may be accessed in jinja templates inside your charts. + Example `POST /security/guest_token` payload: ```json diff --git a/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts b/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts index c63df51d10a6d..ebcd7d6d0d332 100644 --- a/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts +++ b/superset-frontend/cypress-base/cypress/e2e/dashboard/utils.ts @@ -25,7 +25,7 @@ export const WORLD_HEALTH_CHARTS = [ { name: 'Most Populated Countries', viz: 'table' }, { name: "World's Population", viz: 'big_number' }, { name: 'Growth Rate', viz: 'line' }, - { name: 'Rural Breakdown', viz: 'sunburst' }, + { name: 'Rural Breakdown', viz: 'sunburst_v2' }, { name: "World's Pop Growth", viz: 'area' }, { name: 'Life Expectancy VS Rural %', viz: 'bubble' }, { name: 'Treemap', viz: 'treemap_v2' }, diff --git a/superset-frontend/cypress-base/cypress/e2e/explore/visualizations/sunburst.test.js b/superset-frontend/cypress-base/cypress/e2e/explore/visualizations/sunburst.test.js index 03090db9c4ed8..4d55d592c8739 100644 --- a/superset-frontend/cypress-base/cypress/e2e/explore/visualizations/sunburst.test.js +++ b/superset-frontend/cypress-base/cypress/e2e/explore/visualizations/sunburst.test.js @@ -18,17 +18,17 @@ */ describe('Visualization > Sunburst', () => { beforeEach(() => { - cy.intercept('POST', '/superset/explore_json/**').as('getJson'); + cy.intercept('POST', '/api/v1/chart/data**').as('chartData'); }); const SUNBURST_FORM_DATA = { datasource: '2__table', - viz_type: 'sunburst', + viz_type: 'sunburst_v2', slice_id: 47, granularity_sqla: 'year', time_grain_sqla: 'P1D', time_range: 'No filter', - groupby: ['region'], + columns: ['region'], metric: 'sum__SP_POP_TOTL', adhoc_filters: [], row_limit: 50000, @@ -37,32 +37,35 @@ describe('Visualization > Sunburst', () => { function verify(formData) { cy.visitChartByParams(formData); - cy.verifySliceSuccess({ waitAlias: '@getJson', chartSelector: 'svg' }); + cy.verifySliceSuccess({ waitAlias: '@chartData' }); } - it('should work without secondary metric', () => { + // requires the ability to render charts using SVG only for tests + it.skip('should work without secondary metric', () => { verify(SUNBURST_FORM_DATA); - // There should be 7 visible arcs + 1 hidden - cy.get('.chart-container svg g#arcs path').should('have.length', 8); + cy.get('.chart-container svg g path').should('have.length', 7); }); - it('should work with secondary metric', () => { + // requires the ability to render charts using SVG only for tests + it.skip('should work with secondary metric', () => { verify({ ...SUNBURST_FORM_DATA, secondary_metric: 'sum__SP_RUR_TOTL', }); - cy.get('.chart-container svg g#arcs path').should('have.length', 8); + cy.get('.chart-container svg g path').should('have.length', 7); }); - it('should work with multiple groupbys', () => { + // requires the ability to render charts using SVG only for tests + it.skip('should work with multiple columns', () => { verify({ ...SUNBURST_FORM_DATA, - groupby: ['region', 'country_name'], + columns: ['region', 'country_name'], }); - cy.get('.chart-container svg g#arcs path').should('have.length', 117); + cy.get('.chart-container svg g path').should('have.length', 221); }); - it('should work with filter', () => { + // requires the ability to render charts using SVG only for tests + it.skip('should work with filter', () => { verify({ ...SUNBURST_FORM_DATA, adhoc_filters: [ @@ -77,7 +80,7 @@ describe('Visualization > Sunburst', () => { }, ], }); - cy.get('.chart-container svg g#arcs path').should('have.length', 3); + cy.get('.chart-container svg g path').should('have.length', 2); }); it('should allow type to search color schemes', () => { diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 2613026289155..e4af285544aac 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -39,7 +39,6 @@ "@superset-ui/legacy-plugin-chart-rose": "file:./plugins/legacy-plugin-chart-rose", "@superset-ui/legacy-plugin-chart-sankey": "file:./plugins/legacy-plugin-chart-sankey", "@superset-ui/legacy-plugin-chart-sankey-loop": "file:./plugins/legacy-plugin-chart-sankey-loop", - "@superset-ui/legacy-plugin-chart-sunburst": "file:./plugins/legacy-plugin-chart-sunburst", "@superset-ui/legacy-plugin-chart-world-map": "file:./plugins/legacy-plugin-chart-world-map", "@superset-ui/legacy-preset-chart-deckgl": "file:./plugins/legacy-preset-chart-deckgl", "@superset-ui/legacy-preset-chart-nvd3": "file:./plugins/legacy-preset-chart-nvd3", @@ -18338,10 +18337,6 @@ "resolved": "plugins/legacy-plugin-chart-sankey-loop", "link": true }, - "node_modules/@superset-ui/legacy-plugin-chart-sunburst": { - "resolved": "plugins/legacy-plugin-chart-sunburst", - "link": true - }, "node_modules/@superset-ui/legacy-plugin-chart-world-map": { "resolved": "plugins/legacy-plugin-chart-world-map", "link": true @@ -47096,9 +47091,9 @@ } }, "node_modules/node-notifier": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.0.tgz", - "integrity": "sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", + "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", "dev": true, "optional": true, "dependencies": { @@ -61993,13 +61988,13 @@ "license": "Apache-2.0", "dependencies": { "chalk": "^4.0.0", - "lodash": "^4.17.11", + "lodash": "^4.17.21", "yeoman-generator": "^5.7.0", "yosay": "^2.0.2" }, "devDependencies": { "fs-extra": "^10.0.0", - "yeoman-assert": "^3.1.0", + "yeoman-assert": "^3.1.1", "yeoman-test": "^6.2.0" }, "engines": { @@ -62014,8 +62009,8 @@ "@react-icons/all-files": "^4.1.0", "@types/enzyme": "^3.10.5", "@types/react": "*", - "lodash": "^4.17.15", - "prop-types": "^15.7.2" + "lodash": "^4.17.21", + "prop-types": "^15.8.1" }, "peerDependencies": { "@ant-design/icons": "^5.0.1", @@ -62257,7 +62252,6 @@ "@superset-ui/legacy-plugin-chart-rose": "*", "@superset-ui/legacy-plugin-chart-sankey": "*", "@superset-ui/legacy-plugin-chart-sankey-loop": "*", - "@superset-ui/legacy-plugin-chart-sunburst": "*", "@superset-ui/legacy-plugin-chart-time-table": "*", "@superset-ui/legacy-plugin-chart-world-map": "*", "@superset-ui/legacy-preset-chart-deckgl": "*", @@ -62989,7 +62983,7 @@ "d3-array": "^2.0.3", "d3-selection": "^1.4.0", "d3-tip": "^0.9.1", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "peerDependencies": { "@emotion/react": "^11.4.1", @@ -63012,7 +63006,7 @@ "license": "Apache-2.0", "dependencies": { "d3": "^3.5.17", - "prop-types": "^15.6.2", + "prop-types": "^15.8.1", "react": "^16.13.1" }, "peerDependencies": { @@ -63027,7 +63021,7 @@ "dependencies": { "d3": "^3.5.17", "d3-array": "^2.0.3", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "peerDependencies": { "@superset-ui/chart-controls": "*", @@ -63049,7 +63043,7 @@ "license": "Apache-2.0", "dependencies": { "@data-ui/event-flow": "^0.0.84", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "peerDependencies": { "@superset-ui/chart-controls": "*", @@ -63074,7 +63068,7 @@ "d3": "^3.5.17", "d3-svg-legend": "^1.x", "d3-tip": "^0.9.1", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "peerDependencies": { "@emotion/react": "^11.4.1", @@ -63093,7 +63087,7 @@ "@vx/legend": "^0.0.198", "@vx/responsive": "^0.0.199", "@vx/scale": "^0.0.197", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "peerDependencies": { "@superset-ui/chart-controls": "*", @@ -63147,7 +63141,7 @@ "dependencies": { "d3-array": "^2.0.3", "d3-scale": "^3.0.1", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "peerDependencies": { "@superset-ui/chart-controls": "*", @@ -63188,7 +63182,7 @@ "version": "0.18.25", "license": "Apache-2.0", "dependencies": { - "prop-types": "^15.6.2", + "prop-types": "^15.8.1", "react-map-gl": "^6.1.19", "supercluster": "^4.1.1", "viewport-mercator-project": "^6.1.1" @@ -63206,7 +63200,7 @@ "license": "Apache-2.0", "dependencies": { "distributions": "^1.0.0", - "prop-types": "^15.6.2", + "prop-types": "^15.8.1", "reactable": "^1.1.0" }, "peerDependencies": { @@ -63221,7 +63215,7 @@ "license": "Apache-2.0", "dependencies": { "d3": "^3.5.17", - "prop-types": "^15.7.2" + "prop-types": "^15.8.1" }, "peerDependencies": { "@superset-ui/chart-controls": "*", @@ -63236,7 +63230,7 @@ "dependencies": { "d3": "^3.5.17", "d3-hierarchy": "^1.1.8", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "peerDependencies": { "@superset-ui/chart-controls": "*", @@ -63252,7 +63246,7 @@ "dependencies": { "d3": "^3.5.17", "nvd3-fork": "^2.0.5", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "peerDependencies": { "@emotion/react": "^11.4.1", @@ -63268,7 +63262,7 @@ "dependencies": { "d3": "^3.5.17", "d3-sankey": "^0.4.2", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "peerDependencies": { "@superset-ui/chart-controls": "*", @@ -63283,21 +63277,7 @@ "dependencies": { "d3-sankey-diagram": "^0.7.3", "d3-selection": "^1.4.0", - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "@superset-ui/chart-controls": "*", - "@superset-ui/core": "*", - "react": "^16.13.1" - } - }, - "plugins/legacy-plugin-chart-sunburst": { - "name": "@superset-ui/legacy-plugin-chart-sunburst", - "version": "0.18.25", - "license": "Apache-2.0", - "dependencies": { - "d3": "^3.5.17", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "peerDependencies": { "@superset-ui/chart-controls": "*", @@ -63330,7 +63310,7 @@ "d3-array": "^2.4.0", "d3-color": "^1.4.1", "datamaps": "^0.5.8", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "peerDependencies": { "@superset-ui/chart-controls": "*", @@ -63740,12 +63720,12 @@ "d3": "^3.5.17", "d3-tip": "^0.9.1", "dompurify": "^2.0.6", - "fast-safe-stringify": "^2.0.6", - "lodash": "^4.17.11", + "fast-safe-stringify": "^2.1.1", + "lodash": "^4.17.21", "moment": "^2.20.1", "nvd3-fork": "^2.0.5", - "prop-types": "^15.6.2", - "urijs": "^1.19.8" + "prop-types": "^15.8.1", + "urijs": "^1.19.11" }, "peerDependencies": { "@superset-ui/chart-controls": "*", @@ -63760,7 +63740,7 @@ "dependencies": { "d3-array": "^1.2.0", "echarts": "^5.4.1", - "lodash": "^4.17.15", + "lodash": "^4.17.21", "moment": "^2.26.0" }, "peerDependencies": { @@ -63845,7 +63825,7 @@ "memoize-one": "^5.1.1", "react-table": "^7.6.3", "regenerator-runtime": "^0.13.7", - "xss": "^1.0.10" + "xss": "^1.0.14" }, "peerDependencies": { "@superset-ui/chart-controls": "*", @@ -77255,8 +77235,8 @@ "@react-icons/all-files": "^4.1.0", "@types/enzyme": "^3.10.5", "@types/react": "*", - "lodash": "^4.17.15", - "prop-types": "^15.7.2" + "lodash": "^4.17.21", + "prop-types": "^15.8.1" } }, "@superset-ui/core": { @@ -77949,8 +77929,8 @@ "requires": { "chalk": "^4.0.0", "fs-extra": "^10.0.0", - "lodash": "^4.17.11", - "yeoman-assert": "^3.1.0", + "lodash": "^4.17.21", + "yeoman-assert": "^3.1.1", "yeoman-generator": "^5.7.0", "yeoman-test": "^6.2.0", "yosay": "^2.0.2" @@ -77962,7 +77942,7 @@ "d3-array": "^2.0.3", "d3-selection": "^1.4.0", "d3-tip": "^0.9.1", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "dependencies": { "d3-array": { @@ -77979,7 +77959,7 @@ "version": "file:plugins/legacy-plugin-chart-chord", "requires": { "d3": "^3.5.17", - "prop-types": "^15.6.2", + "prop-types": "^15.8.1", "react": "^16.13.1" } }, @@ -77988,7 +77968,7 @@ "requires": { "d3": "^3.5.17", "d3-array": "^2.0.3", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "dependencies": { "d3-array": { @@ -78005,7 +77985,7 @@ "version": "file:plugins/legacy-plugin-chart-event-flow", "requires": { "@data-ui/event-flow": "^0.0.84", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" } }, "@superset-ui/legacy-plugin-chart-heatmap": { @@ -78014,7 +77994,7 @@ "d3": "^3.5.17", "d3-svg-legend": "^1.x", "d3-tip": "^0.9.1", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" } }, "@superset-ui/legacy-plugin-chart-histogram": { @@ -78025,7 +78005,7 @@ "@vx/legend": "^0.0.198", "@vx/responsive": "^0.0.199", "@vx/scale": "^0.0.197", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "dependencies": { "@vx/group": { @@ -78068,7 +78048,7 @@ "requires": { "d3-array": "^2.0.3", "d3-scale": "^3.0.1", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "dependencies": { "d3-array": { @@ -78104,7 +78084,7 @@ "@superset-ui/legacy-plugin-chart-map-box": { "version": "file:plugins/legacy-plugin-chart-map-box", "requires": { - "prop-types": "^15.6.2", + "prop-types": "^15.8.1", "react-map-gl": "^6.1.19", "supercluster": "^4.1.1", "viewport-mercator-project": "^6.1.1" @@ -78114,7 +78094,7 @@ "version": "file:plugins/legacy-plugin-chart-paired-t-test", "requires": { "distributions": "^1.0.0", - "prop-types": "^15.6.2", + "prop-types": "^15.8.1", "reactable": "^1.1.0" } }, @@ -78122,7 +78102,7 @@ "version": "file:plugins/legacy-plugin-chart-parallel-coordinates", "requires": { "d3": "^3.5.17", - "prop-types": "^15.7.2" + "prop-types": "^15.8.1" } }, "@superset-ui/legacy-plugin-chart-partition": { @@ -78130,7 +78110,7 @@ "requires": { "d3": "^3.5.17", "d3-hierarchy": "^1.1.8", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" } }, "@superset-ui/legacy-plugin-chart-rose": { @@ -78138,7 +78118,7 @@ "requires": { "d3": "^3.5.17", "nvd3-fork": "^2.0.5", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" } }, "@superset-ui/legacy-plugin-chart-sankey": { @@ -78146,7 +78126,7 @@ "requires": { "d3": "^3.5.17", "d3-sankey": "^0.4.2", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" } }, "@superset-ui/legacy-plugin-chart-sankey-loop": { @@ -78154,14 +78134,7 @@ "requires": { "d3-sankey-diagram": "^0.7.3", "d3-selection": "^1.4.0", - "prop-types": "^15.6.2" - } - }, - "@superset-ui/legacy-plugin-chart-sunburst": { - "version": "file:plugins/legacy-plugin-chart-sunburst", - "requires": { - "d3": "^3.5.17", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" } }, "@superset-ui/legacy-plugin-chart-world-map": { @@ -78171,7 +78144,7 @@ "d3-array": "^2.4.0", "d3-color": "^1.4.1", "datamaps": "^0.5.8", - "prop-types": "^15.6.2" + "prop-types": "^15.8.1" }, "dependencies": { "d3-array": { @@ -78485,12 +78458,12 @@ "d3": "^3.5.17", "d3-tip": "^0.9.1", "dompurify": "^2.0.6", - "fast-safe-stringify": "^2.0.6", - "lodash": "^4.17.11", + "fast-safe-stringify": "^2.1.1", + "lodash": "^4.17.21", "moment": "^2.20.1", "nvd3-fork": "^2.0.5", - "prop-types": "^15.6.2", - "urijs": "^1.19.8" + "prop-types": "^15.8.1", + "urijs": "^1.19.11" } }, "@superset-ui/plugin-chart-echarts": { @@ -78498,7 +78471,7 @@ "requires": { "d3-array": "^1.2.0", "echarts": "^5.4.1", - "lodash": "^4.17.15", + "lodash": "^4.17.21", "moment": "^2.26.0" } }, @@ -78548,7 +78521,7 @@ "memoize-one": "^5.1.1", "react-table": "^7.6.3", "regenerator-runtime": "^0.13.7", - "xss": "^1.0.10" + "xss": "^1.0.14" }, "dependencies": { "d3-array": { @@ -100821,9 +100794,9 @@ } }, "node-notifier": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.0.tgz", - "integrity": "sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", + "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", "dev": true, "optional": true, "requires": { diff --git a/superset-frontend/package.json b/superset-frontend/package.json index 4aeb85c6e17cb..4cbff6e5e982a 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -105,7 +105,6 @@ "@superset-ui/legacy-plugin-chart-rose": "file:./plugins/legacy-plugin-chart-rose", "@superset-ui/legacy-plugin-chart-sankey": "file:./plugins/legacy-plugin-chart-sankey", "@superset-ui/legacy-plugin-chart-sankey-loop": "file:./plugins/legacy-plugin-chart-sankey-loop", - "@superset-ui/legacy-plugin-chart-sunburst": "file:./plugins/legacy-plugin-chart-sunburst", "@superset-ui/legacy-plugin-chart-world-map": "file:./plugins/legacy-plugin-chart-world-map", "@superset-ui/legacy-preset-chart-deckgl": "file:./plugins/legacy-preset-chart-deckgl", "@superset-ui/legacy-preset-chart-nvd3": "file:./plugins/legacy-preset-chart-nvd3", diff --git a/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts b/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts index 7b8ee63510e51..b2001ec4c136a 100644 --- a/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts +++ b/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts @@ -25,9 +25,11 @@ export enum FeatureFlag { ALERTS_ATTACH_REPORTS = 'ALERTS_ATTACH_REPORTS', ALERT_REPORTS = 'ALERT_REPORTS', ALLOW_FULL_CSV_EXPORT = 'ALLOW_FULL_CSV_EXPORT', + AVOID_COLORS_COLLISION = 'AVOID_COLORS_COLLISION', + CONFIRM_DASHBOARD_DIFF = 'CONFIRM_DASHBOARD_DIFF', + /** @deprecated */ DASHBOARD_CROSS_FILTERS = 'DASHBOARD_CROSS_FILTERS', DASHBOARD_FILTERS_EXPERIMENTAL = 'DASHBOARD_FILTERS_EXPERIMENTAL', - CONFIRM_DASHBOARD_DIFF = 'CONFIRM_DASHBOARD_DIFF', DASHBOARD_NATIVE_FILTERS = 'DASHBOARD_NATIVE_FILTERS', DASHBOARD_VIRTUALIZATION = 'DASHBOARD_VIRTUALIZATION', DASHBOARD_RBAC = 'DASHBOARD_RBAC', @@ -39,9 +41,9 @@ export enum FeatureFlag { EMBEDDABLE_CHARTS = 'EMBEDDABLE_CHARTS', EMBEDDED_SUPERSET = 'EMBEDDED_SUPERSET', ENABLE_ADVANCED_DATA_TYPES = 'ENABLE_ADVANCED_DATA_TYPES', + /** @deprecated */ ENABLE_JAVASCRIPT_CONTROLS = 'ENABLE_JAVASCRIPT_CONTROLS', ENABLE_TEMPLATE_PROCESSING = 'ENABLE_TEMPLATE_PROCESSING', - ENABLE_TEMPLATE_REMOVE_FILTERS = 'ENABLE_TEMPLATE_REMOVE_FILTERS', ESCAPE_MARKDOWN_HTML = 'ESCAPE_MARKDOWN_HTML', ESTIMATE_QUERY_COST = 'ESTIMATE_QUERY_COST', GENERIC_CHART_AXES = 'GENERIC_CHART_AXES', @@ -52,12 +54,11 @@ export enum FeatureFlag { SHARE_QUERIES_VIA_KV_STORE = 'SHARE_QUERIES_VIA_KV_STORE', SQLLAB_BACKEND_PERSISTENCE = 'SQLLAB_BACKEND_PERSISTENCE', SQL_VALIDATORS_BY_ENGINE = 'SQL_VALIDATORS_BY_ENGINE', + SSH_TUNNELING = 'SSH_TUNNELING', + TAGGING_SYSTEM = 'TAGGING_SYSTEM', THUMBNAILS = 'THUMBNAILS', USE_ANALAGOUS_COLORS = 'USE_ANALAGOUS_COLORS', - TAGGING_SYSTEM = 'TAGGING_SYSTEM', VERSIONED_EXPORT = 'VERSIONED_EXPORT', - SSH_TUNNELING = 'SSH_TUNNELING', - AVOID_COLORS_COLLISION = 'AVOID_COLORS_COLLISION', } export type ScheduleQueriesProps = { JSONSCHEMA: { diff --git a/superset-frontend/packages/superset-ui-core/test/chart/fixtures/formData.ts b/superset-frontend/packages/superset-ui-core/test/chart/fixtures/formData.ts index 9d926f46131bd..88a78c6017c4e 100644 --- a/superset-frontend/packages/superset-ui-core/test/chart/fixtures/formData.ts +++ b/superset-frontend/packages/superset-ui-core/test/chart/fixtures/formData.ts @@ -56,13 +56,13 @@ export const wordCloudFormData = { export const sunburstFormData = { datasource: '2__table', - viz_type: 'sunburst', + viz_type: 'sunburst_v2', slice_id: 47, url_params: {}, granularity_sqla: 'year', time_grain_sqla: 'P1D', time_range: '2011-01-01 : 2011-01-01', - groupby: ['region', 'country_name'], + columns: ['region', 'country_name'], metric: 'sum__SP_POP_TOTL', secondary_metric: 'sum__SP_RUR_TOTL', adhoc_filters: [], diff --git a/superset-frontend/packages/superset-ui-demo/package.json b/superset-frontend/packages/superset-ui-demo/package.json index 883165a532816..7c04c590a388a 100644 --- a/superset-frontend/packages/superset-ui-demo/package.json +++ b/superset-frontend/packages/superset-ui-demo/package.json @@ -80,7 +80,6 @@ "@superset-ui/legacy-plugin-chart-rose": "*", "@superset-ui/legacy-plugin-chart-sankey": "*", "@superset-ui/legacy-plugin-chart-sankey-loop": "*", - "@superset-ui/legacy-plugin-chart-sunburst": "*", "@superset-ui/legacy-plugin-chart-time-table": "*", "@superset-ui/legacy-plugin-chart-world-map": "*", "@superset-ui/legacy-preset-chart-deckgl": "*", diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-plugin-chart-sunburst/Stories.tsx b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-plugin-chart-sunburst/Stories.tsx deleted file mode 100644 index 35b6388be7650..0000000000000 --- a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-plugin-chart-sunburst/Stories.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* eslint-disable no-magic-numbers */ -import React from 'react'; -import { SuperChart } from '@superset-ui/core'; -import SunburstChartPlugin from '@superset-ui/legacy-plugin-chart-sunburst'; -import ResizableChartDemo from '../../../shared/components/ResizableChartDemo'; -import data from './data'; - -new SunburstChartPlugin().configure({ key: 'sunburst' }).register(); - -export default { - title: 'Legacy Chart Plugins/legacy-plugin-chart-sunburst', -}; - -export const basic = () => ( - -); - -export const resizable = () => ( - - {({ width, height }) => ( - - )} - -); diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-plugin-chart-sunburst/data.ts b/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-plugin-chart-sunburst/data.ts deleted file mode 100644 index 69df74de4dd38..0000000000000 --- a/superset-frontend/packages/superset-ui-demo/storybook/stories/plugins/legacy-plugin-chart-sunburst/data.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* eslint-disable sort-keys, no-magic-numbers */ -export default [ - ['East Asia & Pacific', 'China', 1344130000.0, 664363135.0], - ['South Asia', 'India', 1247446011.0, 857294797.0], - ['North America', 'United States', 311721632.0, 59414143.0], - ['East Asia & Pacific', 'Indonesia', 244808254.0, 120661092.0], - ['Latin America & Caribbean', 'Brazil', 200517584.0, 30833589.0], - ['South Asia', 'Pakistan', 173669648.0, 109399721.0], - ['Sub-Saharan Africa', 'Nigeria', 163770669.0, 91118725.0], - ['South Asia', 'Bangladesh', 153405612.0, 105504710.0], - ['Europe & Central Asia', 'Russian Federation', 142960868.0, 37552961.0], - ['East Asia & Pacific', 'Japan', 127817277.0, 11186568.0], -]; diff --git a/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-chart/ChartDataProviderStories.tsx b/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-chart/ChartDataProviderStories.tsx index ddf21df792a24..1abc9ee65ced6 100644 --- a/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-chart/ChartDataProviderStories.tsx +++ b/superset-frontend/packages/superset-ui-demo/storybook/stories/superset-ui-chart/ChartDataProviderStories.tsx @@ -27,7 +27,6 @@ import { } from '@superset-ui/core'; import { BigNumberChartPlugin } from '@superset-ui/plugin-chart-echarts'; import LegacySankeyPlugin from '@superset-ui/legacy-plugin-chart-sankey'; -import LegacySunburstPlugin from '@superset-ui/legacy-plugin-chart-sunburst'; import { WordCloudChartPlugin } from '@superset-ui/plugin-chart-word-cloud'; import { @@ -50,8 +49,6 @@ new BigNumberChartPlugin().configure({ key: BIG_NUMBER }).register(); // eslint-disable-next-line new LegacySankeyPlugin().configure({ key: SANKEY }).register(); // eslint-disable-next-line -new LegacySunburstPlugin().configure({ key: SUNBURST }).register(); -// eslint-disable-next-line new WordCloudChartPlugin().configure({ key: WORD_CLOUD }).register(); const VIS_TYPES = [BIG_NUMBER, SANKEY, SUNBURST, WORD_CLOUD, WORD_CLOUD_LEGACY]; diff --git a/superset-frontend/plugins/legacy-plugin-chart-sunburst/CHANGELOG.md b/superset-frontend/plugins/legacy-plugin-chart-sunburst/CHANGELOG.md deleted file mode 100644 index 01a75d202c785..0000000000000 --- a/superset-frontend/plugins/legacy-plugin-chart-sunburst/CHANGELOG.md +++ /dev/null @@ -1,35 +0,0 @@ - - -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -# [0.18.0](https://github.com/apache-superset/superset-ui/compare/v0.17.87...v0.18.0) (2021-08-30) - -**Note:** Version bump only for package @superset-ui/legacy-plugin-chart-sunburst - - - - - -## [0.17.61](https://github.com/apache-superset/superset-ui/compare/v0.17.60...v0.17.61) (2021-07-02) - -**Note:** Version bump only for package @superset-ui/legacy-plugin-chart-sunburst diff --git a/superset-frontend/plugins/legacy-plugin-chart-sunburst/README.md b/superset-frontend/plugins/legacy-plugin-chart-sunburst/README.md deleted file mode 100644 index 20bfb8a483509..0000000000000 --- a/superset-frontend/plugins/legacy-plugin-chart-sunburst/README.md +++ /dev/null @@ -1,52 +0,0 @@ - - -## @superset-ui/legacy-plugin-chart-sunburst - -[![Version](https://img.shields.io/npm/v/@superset-ui/legacy-plugin-chart-sunburst.svg?style=flat-square)](https://www.npmjs.com/package/@superset-ui/legacy-plugin-chart-sunburst) -[![David (path)](https://img.shields.io/david/apache-superset/superset-ui-plugins.svg?path=packages%2Fsuperset-ui-legacy-plugin-chart-sunburst&style=flat-square)](https://david-dm.org/apache-superset/superset-ui-plugins?path=packages/superset-ui-legacy-plugin-chart-sunburst) - -This plugin provides Sunburst for Superset. - -### Usage - -Configure `key`, which can be any `string`, and register the plugin. This `key` will be used to -lookup this chart throughout the app. - -```js -import SunburstChartPlugin from '@superset-ui/legacy-plugin-chart-sunburst'; - -new SunburstChartPlugin().configure({ key: 'sunburst' }).register(); -``` - -Then use it via `SuperChart`. See -[storybook](https://apache-superset.github.io/superset-ui-plugins/?selectedKind=plugin-chart-sunburst) -for more details. - -```js - -``` diff --git a/superset-frontend/plugins/legacy-plugin-chart-sunburst/package.json b/superset-frontend/plugins/legacy-plugin-chart-sunburst/package.json deleted file mode 100644 index fd2a5405a384c..0000000000000 --- a/superset-frontend/plugins/legacy-plugin-chart-sunburst/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "@superset-ui/legacy-plugin-chart-sunburst", - "version": "0.18.25", - "description": "Superset Legacy Chart - Sunburst", - "keywords": [ - "superset" - ], - "homepage": "https://github.com/apache/superset/tree/master/superset-frontend/plugins/legacy-plugin-chart-sunburst#readme", - "bugs": { - "url": "https://github.com/apache/superset/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/apache/superset.git", - "directory": "superset-frontend/plugins/legacy-plugin-chart-sunburst" - }, - "license": "Apache-2.0", - "author": "Superset", - "main": "lib/index.js", - "module": "esm/index.js", - "files": [ - "esm", - "lib" - ], - "dependencies": { - "d3": "^3.5.17", - "prop-types": "^15.8.1" - }, - "peerDependencies": { - "@superset-ui/chart-controls": "*", - "@superset-ui/core": "*", - "react": "^16.13.1" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/ReactSunburst.jsx b/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/ReactSunburst.jsx deleted file mode 100644 index 10e959285bb4b..0000000000000 --- a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/ReactSunburst.jsx +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import { reactify, styled } from '@superset-ui/core'; -import Component from './Sunburst'; - -const ReactComponent = reactify(Component); - -const Sunburst = ({ className, ...otherProps }) => ( -
- -
-); - -export default styled(Sunburst)` - ${({ theme }) => ` - .superset-legacy-chart-sunburst text { - text-rendering: optimizeLegibility; - } - .superset-legacy-chart-sunburst path { - stroke: ${theme.colors.grayscale.light2}; - stroke-width: 0.5px; - } - .superset-legacy-chart-sunburst .center-label { - text-anchor: middle; - fill: ${theme.colors.grayscale.dark1}; - pointer-events: none; - } - .superset-legacy-chart-sunburst .path-abs-percent { - font-size: ${theme.typography.sizes.m}px; - font-weight: ${theme.typography.weights.bold}; - } - .superset-legacy-chart-sunburst .path-cond-percent { - font-size: ${theme.typography.sizes.s}px; - } - .superset-legacy-chart-sunburst .path-metrics { - color: ${theme.colors.grayscale.base}; - } - .superset-legacy-chart-sunburst .path-ratio { - color: ${theme.colors.grayscale.base}; - } - - .superset-legacy-chart-sunburst .breadcrumbs text { - font-weight: ${theme.typography.weights.bold}; - font-size: ${theme.typography.sizes.m}px; - text-anchor: middle; - fill: ${theme.colors.grayscale.dark1}; - } - `} -`; diff --git a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/Sunburst.js b/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/Sunburst.js deleted file mode 100644 index 138788495c894..0000000000000 --- a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/Sunburst.js +++ /dev/null @@ -1,531 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -/* eslint-disable no-param-reassign, react/sort-prop-types */ -import d3 from 'd3'; -import PropTypes from 'prop-types'; -import { - getNumberFormatter, - NumberFormats, - CategoricalColorNamespace, - getSequentialSchemeRegistry, - t, -} from '@superset-ui/core'; -import wrapSvgText from './utils/wrapSvgText'; - -const propTypes = { - // Each row is an array of [hierarchy-lvl1, hierarchy-lvl2, metric1, metric2] - // hierarchy-lvls are string. metrics are number - data: PropTypes.arrayOf(PropTypes.array), - width: PropTypes.number, - height: PropTypes.number, - colorScheme: PropTypes.string, - linearColorScheme: PropTypes.string, - numberFormat: PropTypes.string, - metrics: PropTypes.arrayOf( - PropTypes.oneOfType([ - PropTypes.string, - PropTypes.object, // The metric object - ]), - ), -}; - -function metricLabel(metric) { - return typeof metric === 'string' || metric instanceof String - ? metric - : metric.label; -} - -// Given a node in a partition layout, return an array of all of its ancestor -// nodes, highest first, but excluding the root. -function getAncestors(node) { - const path = []; - let current = node; - while (current.parent) { - path.unshift(current); - current = current.parent; - } - - return path; -} - -function buildHierarchy(rows) { - const root = { - name: 'root', - children: [], - }; - - // each record [groupby1val, groupby2val, ( or 0)n, m1, m2] - rows.forEach(row => { - const m1 = Number(row[row.length - 2]); - const m2 = Number(row[row.length - 1]); - const levels = row.slice(0, -2); - if (Number.isNaN(m1)) { - // e.g. if this is a header row - return; - } - let currentNode = root; - for (let level = 0; level < levels.length; level += 1) { - const children = currentNode.children || []; - const node = levels[level]; - const nodeName = node ? node.toString() : t('N/A'); - // If the next node has the name '0', it will - const isLeafNode = level >= levels.length - 1 || levels[level + 1] === 0; - let childNode; - - if (!isLeafNode) { - childNode = children.find( - child => child.name === nodeName && child.level === level, - ); - - if (!childNode) { - childNode = { - name: nodeName, - children: [], - level, - }; - children.push(childNode); - } - currentNode = childNode; - } else if (nodeName !== 0) { - // Reached the end of the sequence; create a leaf node. - childNode = { - name: nodeName, - m1, - m2, - }; - children.push(childNode); - } - } - }); - - function recurse(node) { - if (node.children) { - let sums; - let m1 = 0; - let m2 = 0; - for (let i = 0; i < node.children.length; i += 1) { - sums = recurse(node.children[i]); - m1 += sums[0]; - m2 += sums[1]; - } - node.m1 = m1; - node.m2 = m2; - } - - return [node.m1, node.m2]; - } - - recurse(root); - - return root; -} - -function getResponsiveContainerClass(width) { - if (width > 500) { - return 'l'; - } - - if (width > 200 && width <= 500) { - return 'm'; - } - - return 's'; -} - -function getYOffset(width) { - if (width > 500) { - return ['0', '20', '40', '60']; - } - - if (width > 200 && width <= 500) { - return ['0', '15', '30', '45']; - } - - return ['0', '10', '20', '30']; -} - -// Modified from http://bl.ocks.org/kerryrodden/7090426 -function Sunburst(element, props) { - const container = d3.select(element); - const { - data, - width, - height, - colorScheme, - linearColorScheme, - metrics, - numberFormat, - sliceId, - } = props; - const responsiveClass = getResponsiveContainerClass(width); - const isSmallWidth = responsiveClass === 's'; - container.attr('class', `superset-legacy-chart-sunburst ${responsiveClass}`); - // vars with shared scope within this function - const margin = { top: 10, right: 5, bottom: 10, left: 5 }; - const containerWidth = width; - const containerHeight = height; - const breadcrumbHeight = containerHeight * 0.085; - const visWidth = containerWidth - margin.left - margin.right; - const visHeight = - containerHeight - margin.top - margin.bottom - breadcrumbHeight; - const radius = Math.min(visWidth, visHeight) / 2; - - let colorByCategory = true; // color by category if primary/secondary metrics match - let maxBreadcrumbs; - let breadcrumbDims; // set based on data - let totalSize; // total size of all segments; set after loading the data. - let breadcrumbs; - let vis; - let arcs; - let gMiddleText; // dom handles - - const categoricalColorScale = CategoricalColorNamespace.getScale(colorScheme); - let linearColorScale; - - // Helper + path gen functions - const partition = d3.layout - .partition() - .size([2 * Math.PI, radius * radius]) - .value(d => d.m1); - - const arc = d3.svg - .arc() - .startAngle(d => d.x) - .endAngle(d => d.x + d.dx) - .innerRadius(d => Math.sqrt(d.y)) - .outerRadius(d => Math.sqrt(d.y + d.dy)); - - const formatNum = getNumberFormatter( - numberFormat || NumberFormats.SI_3_DIGIT, - ); - const formatPerc = getNumberFormatter(NumberFormats.PERCENT_3_POINT); - - container.select('svg').remove(); - - const svg = container - .append('svg:svg') - .attr('width', containerWidth) - .attr('height', containerHeight); - - function createBreadcrumbs(firstRowData) { - // -2 bc row contains 2x metrics, +extra for %label and buffer - maxBreadcrumbs = firstRowData.length - 2 + 1; - breadcrumbDims = { - width: visWidth / maxBreadcrumbs, - height: breadcrumbHeight * 0.8, // more margin - spacing: 3, - tipTailWidth: 10, - }; - - breadcrumbs = svg - .append('svg:g') - .attr('class', 'breadcrumbs') - .attr('transform', `translate(${margin.left},${margin.top})`); - - breadcrumbs.append('svg:text').attr('class', 'end-label'); - } - - // Generate a string that describes the points of a breadcrumb polygon. - function breadcrumbPoints(d, i) { - const points = []; - if (isSmallWidth) { - points.push('0,0'); - points.push(`${width},0`); - points.push(`${width},0`); - points.push(`${width},${breadcrumbDims.height}`); - points.push(`0,${breadcrumbDims.height}`); - if (i > 0) { - // Leftmost breadcrumb; don't include 6th vertex. - // points.push(`${breadcrumbDims.tipTailWidth},${breadcrumbDims.height / 2}`); - } - } else { - points.push('0,0'); - points.push(`${breadcrumbDims.width},0`); - points.push( - `${breadcrumbDims.width + breadcrumbDims.tipTailWidth},${ - breadcrumbDims.height / 2 - }`, - ); - points.push(`${breadcrumbDims.width},${breadcrumbDims.height}`); - points.push(`0,${breadcrumbDims.height}`); - if (i > 0) { - // Leftmost breadcrumb; don't include 6th vertex. - points.push( - `${breadcrumbDims.tipTailWidth},${breadcrumbDims.height / 2}`, - ); - } - } - - return points.join(' '); - } - - function updateBreadcrumbs(sequenceArray, percentageString) { - const breadcrumbWidth = isSmallWidth ? width : breadcrumbDims.width; - const g = breadcrumbs - .selectAll('g') - .data(sequenceArray, d => d.name + d.depth); - - // Add breadcrumb and label for entering nodes. - const entering = g.enter().append('svg:g'); - - entering - .append('svg:polygon') - .attr('points', breadcrumbPoints) - .style('fill', d => - colorByCategory - ? categoricalColorScale(d.name, sliceId) - : linearColorScale(d.m2 / d.m1), - ); - - entering - .append('svg:text') - .attr('x', (breadcrumbWidth + breadcrumbDims.tipTailWidth) / 2) - .attr('y', breadcrumbDims.height / 4) - .attr('dy', '0.35em') - .style('fill', d => { - // Make text white or black based on the lightness of the background - const col = d3.hsl( - colorByCategory - ? categoricalColorScale(d.name, sliceId) - : linearColorScale(d.m2 / d.m1), - ); - - return col.l < 0.5 ? 'white' : 'black'; - }) - .attr('class', 'step-label') - .text(d => d.name.replace(/_/g, ' ')) - .call(wrapSvgText, breadcrumbWidth, breadcrumbDims.height / 2); - - // Set position for entering and updating nodes. - g.attr('transform', (d, i) => { - if (isSmallWidth) { - return `translate(0, ${ - i * (breadcrumbDims.height + breadcrumbDims.spacing) - })`; - } - return `translate(${ - i * (breadcrumbDims.width + breadcrumbDims.spacing) - }, 0)`; - }); - - // Remove exiting nodes. - g.exit().remove(); - - // Now move and update the percentage at the end. - breadcrumbs - .select('.end-label') - .attr('x', () => { - if (isSmallWidth) { - return (breadcrumbWidth + breadcrumbDims.tipTailWidth) / 2; - } - - return ( - (sequenceArray.length + 0.5) * - (breadcrumbDims.width + breadcrumbDims.spacing) - ); - }) - .attr('y', () => { - if (isSmallWidth) { - return (sequenceArray.length + 1) * breadcrumbDims.height; - } - - return breadcrumbDims.height / 2; - }) - .attr('dy', '0.35em') - .text(percentageString); - - // Make the breadcrumb trail visible, if it's hidden. - breadcrumbs.style('visibility', null); - } - - // Fade all but the current sequence, and show it in the breadcrumb trail. - function mouseenter(d) { - const sequenceArray = getAncestors(d); - const parentOfD = sequenceArray[sequenceArray.length - 2] || null; - - const absolutePercentage = (d.m1 / totalSize).toPrecision(3); - const conditionalPercentage = parentOfD - ? (d.m1 / parentOfD.m1).toPrecision(3) - : null; - - const absolutePercString = formatPerc(absolutePercentage); - const conditionalPercString = parentOfD - ? formatPerc(conditionalPercentage) - : ''; - - // 3 levels of text if inner-most level, 4 otherwise - const yOffsets = getYOffset(width); - let offsetIndex = 0; - - // If metrics match, assume we are coloring by category - const metricsMatch = Math.abs(d.m1 - d.m2) < 0.00001; - - gMiddleText.selectAll('*').remove(); - - offsetIndex += 1; - gMiddleText - .append('text') - .attr('class', 'path-abs-percent') - .attr('y', yOffsets[offsetIndex]) - // eslint-disable-next-line prefer-template - .text(absolutePercString + ' ' + t('of total')); - - const OF_PARENT_TEXT = t('of parent'); - - if (conditionalPercString) { - offsetIndex += 1; - gMiddleText - .append('text') - .attr('class', 'path-cond-percent') - .attr('y', yOffsets[offsetIndex]) - .text(`${conditionalPercString} ${OF_PARENT_TEXT}`); - } - - offsetIndex += 1; - gMiddleText - .append('text') - .attr('class', 'path-metrics') - .attr('y', yOffsets[offsetIndex]) - .text( - `${metricLabel(metrics[0])}: ${formatNum(d.m1)}${ - metricsMatch ? '' : `, ${metricLabel(metrics[1])}: ${formatNum(d.m2)}` - }`, - ); - - offsetIndex += 1; - gMiddleText - .append('text') - .attr('class', 'path-ratio') - .attr('y', yOffsets[offsetIndex]) - .text( - metricsMatch - ? '' - : `${metricLabel(metrics[1])}/${metricLabel( - metrics[0], - )}: ${formatPerc(d.m2 / d.m1)}`, - ); - - // Reset and fade all the segments. - arcs - .selectAll('path') - .style('stroke-width', null) - .style('stroke', null) - .style('opacity', 0.3); - - // Then highlight only those that are an ancestor of the current segment. - arcs - .selectAll('path') - .filter(node => sequenceArray.includes(node)) - .style('opacity', 1) - .style('stroke', '#aaa'); - - updateBreadcrumbs(sequenceArray, absolutePercString); - } - - // Restore everything to full opacity when moving off the visualization. - function mouseleave() { - // Hide the breadcrumb trail - breadcrumbs.style('visibility', 'hidden'); - - gMiddleText.selectAll('*').remove(); - - // Deactivate all segments during transition. - arcs.selectAll('path').on('mouseenter', null); - - // Transition each segment to full opacity and then reactivate it. - arcs - .selectAll('path') - .transition() - .duration(200) - .style('opacity', 1) - .style('stroke', null) - .style('stroke-width', null) - .each('end', function end() { - d3.select(this).on('mouseenter', mouseenter); - }); - } - - // Main function to draw and set up the visualization, once we have the data. - function createVisualization(rows) { - const root = buildHierarchy(rows); - maxBreadcrumbs = rows[0].length - 2; - vis = svg - .append('svg:g') - .attr('class', 'sunburst-vis') - .attr( - 'transform', - 'translate(' + - `${margin.left + visWidth / 2},` + - `${ - margin.top + - (isSmallWidth - ? breadcrumbHeight * maxBreadcrumbs - : breadcrumbHeight) + - visHeight / 2 - }` + - ')', - ) - .on('mouseleave', mouseleave); - - arcs = vis.append('svg:g').attr('id', 'arcs'); - - gMiddleText = vis.append('svg:g').attr('class', 'center-label'); - - // Bounding circle underneath the sunburst, to make it easier to detect - // when the mouse leaves the parent g. - arcs.append('svg:circle').attr('r', radius).style('opacity', 0); - - // For efficiency, filter nodes to keep only those large enough to see. - const nodes = partition.nodes(root).filter(d => d.dx > 0.005); // 0.005 radians = 0.29 degrees - - if (metrics[0] !== metrics[1] && metrics[1]) { - colorByCategory = false; - const ext = d3.extent(nodes, d => d.m2 / d.m1); - linearColorScale = getSequentialSchemeRegistry() - .get(linearColorScheme) - .createLinearScale(ext); - } - - arcs - .selectAll('path') - .data(nodes) - .enter() - .append('svg:path') - .attr('display', d => (d.depth ? null : 'none')) - .attr('d', arc) - .attr('fill-rule', 'evenodd') - .style('fill', d => - colorByCategory - ? categoricalColorScale(d.name, sliceId) - : linearColorScale(d.m2 / d.m1), - ) - .style('opacity', 1) - .on('mouseenter', mouseenter); - - // Get total size of the tree = value of root node from partition. - totalSize = root.value; - } - createBreadcrumbs(data[0]); - createVisualization(data); -} - -Sunburst.displayName = 'Sunburst'; -Sunburst.propTypes = propTypes; - -export default Sunburst; diff --git a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts b/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts deleted file mode 100644 index 32b56fb9e4af2..0000000000000 --- a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/controlPanel.ts +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { t } from '@superset-ui/core'; -import { - ControlPanelConfig, - ControlPanelsContainerProps, - getStandardizedControls, - sections, -} from '@superset-ui/chart-controls'; - -const config: ControlPanelConfig = { - controlPanelSections: [ - sections.legacyRegularTime, - { - label: t('Query'), - expanded: true, - controlSetRows: [ - ['groupby'], - ['metric'], - ['secondary_metric'], - ['adhoc_filters'], - ['row_limit'], - [ - { - name: 'sort_by_metric', - config: { - type: 'CheckboxControl', - label: t('Sort by metric'), - description: t( - 'Whether to sort results by the selected metric in descending order.', - ), - }, - }, - ], - ], - }, - { - label: t('Chart Options'), - expanded: true, - controlSetRows: [['color_scheme'], ['linear_color_scheme']], - }, - ], - controlOverrides: { - metric: { - label: t('Primary Metric'), - description: t( - 'The primary metric is used to define the arc segment sizes', - ), - }, - secondary_metric: { - label: t('Secondary Metric'), - default: null, - description: t( - '[optional] this secondary metric is used to ' + - 'define the color as a ratio against the primary metric. ' + - 'When omitted, the color is categorical and based on labels', - ), - }, - color_scheme: { - description: t( - 'When only a primary metric is provided, a categorical color scale is used.', - ), - visibility: ({ controls }: ControlPanelsContainerProps) => - Boolean( - !controls?.secondary_metric?.value || - controls?.secondary_metric?.value === controls?.metric.value, - ), - }, - linear_color_scheme: { - description: t( - 'When a secondary metric is provided, a linear color scale is used.', - ), - visibility: ({ controls }: ControlPanelsContainerProps) => - Boolean( - controls?.secondary_metric?.value && - controls?.secondary_metric?.value !== controls?.metric.value, - ), - }, - groupby: { - label: t('Hierarchy'), - description: t('This defines the level of the hierarchy'), - }, - }, - formDataOverrides: formData => ({ - ...formData, - groupby: getStandardizedControls().popAllColumns(), - metric: getStandardizedControls().shiftMetric(), - secondary_metric: getStandardizedControls().shiftMetric(), - }), -}; - -export default config; diff --git a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/images/example.png b/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/images/example.png deleted file mode 100644 index 003d00e966074..0000000000000 Binary files a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/images/example.png and /dev/null differ diff --git a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/images/thumbnail.png b/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/images/thumbnail.png deleted file mode 100644 index 46f8262b87342..0000000000000 Binary files a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/images/thumbnail.png and /dev/null differ diff --git a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/images/thumbnailLarge.png b/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/images/thumbnailLarge.png deleted file mode 100644 index 6c4706bf76714..0000000000000 Binary files a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/images/thumbnailLarge.png and /dev/null differ diff --git a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js b/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js deleted file mode 100644 index c3ea740e2531a..0000000000000 --- a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/index.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core'; -import transformProps from './transformProps'; -import thumbnail from './images/thumbnail.png'; -import example from './images/example.png'; -import controlPanel from './controlPanel'; - -const metadata = new ChartMetadata({ - category: t('Part of a Whole'), - credits: ['https://bl.ocks.org/kerryrodden/7090426'], - description: t( - 'Uses circles to visualize the flow of data through different stages of a system. Hover over individual paths in the visualization to understand the stages a value took. Useful for multi-stage, multi-group visualizing funnels and pipelines.', - ), - exampleGallery: [{ url: example }], - name: t('Sunburst Chart'), - tags: [t('Aesthetic'), t('Legacy'), t('Multi-Levels'), t('Proportional')], - thumbnail, - useLegacyApi: true, -}); - -export default class SunburstChartPlugin extends ChartPlugin { - constructor() { - super({ - loadChart: () => import('./ReactSunburst'), - metadata, - transformProps, - controlPanel, - }); - } -} diff --git a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/transformProps.js b/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/transformProps.js deleted file mode 100644 index 92c4d99f00e41..0000000000000 --- a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/transformProps.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -export default function transformProps(chartProps) { - const { width, height, formData, queriesData, datasource } = chartProps; - const { colorScheme, linearColorScheme, metric, secondaryMetric, sliceId } = - formData; - - const returnProps = { - width, - height, - data: queriesData[0].data, - colorScheme, - linearColorScheme, - metrics: [metric, secondaryMetric], - sliceId, - }; - - if (datasource && datasource.metrics) { - const metricWithFormat = datasource.metrics.find( - ({ metric_name: metricName, d3format }) => - metricName === formData.metric && d3format, - ); - if (metricWithFormat) { - Object.assign(returnProps, { numberFormat: metricWithFormat.d3format }); - } - } - - return returnProps; -} diff --git a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/utils/wrapSvgText.js b/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/utils/wrapSvgText.js deleted file mode 100644 index 12cdead8d34ee..0000000000000 --- a/superset-frontend/plugins/legacy-plugin-chart-sunburst/src/utils/wrapSvgText.js +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* - Utility function that takes a d3 svg:text selection and a max width, and splits the - text's text across multiple tspan lines such that any given line does not exceed max width - - If text does not span multiple lines AND adjustedY is passed, - will set the text to the passed val -*/ -import d3 from 'd3'; - -export default function wrapSvgText(text, width, adjustedY) { - const lineHeight = 1; - // ems - text.each(function each() { - const d3Text = d3.select(this); - const words = d3Text.text().split(/\s+/); - let line = []; - let lineNumber = 0; - const x = d3Text.attr('x'); - const y = d3Text.attr('y'); - const dy = parseFloat(d3Text.attr('dy')); - let tspan = d3Text - .text(null) - .append('tspan') - .attr('x', x) - .attr('y', y) - .attr('dy', `${dy}em`); - - let didWrap = false; - words.forEach(word => { - line.push(word); - tspan.text(line.join(' ')); - if (tspan.node().getComputedTextLength() > width) { - lineNumber += 1; - line.pop(); - // remove word that pushes over the limit - tspan.text(line.join(' ')); - line = [word]; - tspan = d3Text - .append('tspan') - .attr('x', x) - .attr('y', y) - .attr('dy', `${lineNumber * lineHeight + dy}em`) - .text(word); - didWrap = true; - } - }); - - if (!didWrap && typeof adjustedY !== 'undefined') { - tspan.attr('y', adjustedY); - } - }); -} diff --git a/superset-frontend/plugins/legacy-plugin-chart-sunburst/tsconfig.json b/superset-frontend/plugins/legacy-plugin-chart-sunburst/tsconfig.json deleted file mode 100644 index b6bfaa2d98446..0000000000000 --- a/superset-frontend/plugins/legacy-plugin-chart-sunburst/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "declarationDir": "lib", - "outDir": "lib", - "rootDir": "src" - }, - "exclude": [ - "lib", - "test" - ], - "extends": "../../tsconfig.json", - "include": [ - "src/**/*", - "types/**/*", - "../../types/**/*" - ], - "references": [ - { - "path": "../../packages/superset-ui-chart-controls" - }, - { - "path": "../../packages/superset-ui-core" - } - ] -} diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts index 42087078030b9..43309d5d27c2f 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Sunburst/index.ts @@ -43,7 +43,7 @@ export default class EchartsSunburstChartPlugin extends EchartsChartPlugin { 'Uses circles to visualize the flow of data through different stages of a system. Hover over individual paths in the visualization to understand the stages a value took. Useful for multi-stage, multi-group visualizing funnels and pipelines.', ), exampleGallery: [{ url: example1 }, { url: example2 }], - name: t('Sunburst Chart v2'), + name: t('Sunburst Chart'), tags: [ t('ECharts'), t('Aesthetic'), diff --git a/superset-frontend/spec/fixtures/mockSliceEntities.js b/superset-frontend/spec/fixtures/mockSliceEntities.js index 73e96ae871f3f..2737d35d01d40 100644 --- a/superset-frontend/spec/fixtures/mockSliceEntities.js +++ b/superset-frontend/spec/fixtures/mockSliceEntities.js @@ -149,7 +149,7 @@ export const sliceEntitiesForDashboard = { slice_url: '/explore/?form_data=%7B%22slice_id%22%3A%20133%7D', slice_name: 'Rural Breakdown', form_data: {}, - viz_type: 'sunburst', + viz_type: 'sunburst_v2', datasource: '2__table', description: null, description_markeddown: '', diff --git a/superset-frontend/src/dashboard/components/SliceHeaderControls/SliceHeaderControls.test.tsx b/superset-frontend/src/dashboard/components/SliceHeaderControls/SliceHeaderControls.test.tsx index add9bb97396d6..2d7b5c05bdf64 100644 --- a/superset-frontend/src/dashboard/components/SliceHeaderControls/SliceHeaderControls.test.tsx +++ b/superset-frontend/src/dashboard/components/SliceHeaderControls/SliceHeaderControls.test.tsx @@ -37,7 +37,7 @@ jest.mock('src/components/Dropdown', () => { }; }); -const createProps = (viz_type = 'sunburst') => +const createProps = (viz_type = 'sunburst_v2') => ({ addDangerToast: jest.fn(), addSuccessToast: jest.fn(), @@ -59,7 +59,9 @@ const createProps = (viz_type = 'sunburst') => adhoc_filters: [], color_scheme: 'supersetColors', datasource: '58__table', - groupby: ['product_category', 'clinical_stage'], + ...(viz_type === 'sunburst_v2' + ? { columns: ['product_category', 'clinical_stage'] } + : { groupby: ['product_category', 'clinical_stage'] }), linear_color_scheme: 'schemeYlOrBr', metric: 'count', queryFields: { @@ -93,7 +95,7 @@ const createProps = (viz_type = 'sunburst') => chartStatus: 'rendered', showControls: true, supersetCanShare: true, - formData: { slice_id: 1, datasource: '58__table', viz_type: 'sunburst' }, + formData: { slice_id: 1, datasource: '58__table', viz_type: 'sunburst_v2' }, exploreUrl: '/explore', } as SliceHeaderControlsProps); diff --git a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx index 2d14376516931..8934ca9cf0318 100644 --- a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx +++ b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx @@ -93,7 +93,6 @@ const DEFAULT_ORDER = [ 'deck_screengrid', 'treemap_v2', 'box_plot', - 'sunburst', 'sankey', 'word_cloud', 'mapbox', diff --git a/superset-frontend/src/visualizations/presets/MainPreset.js b/superset-frontend/src/visualizations/presets/MainPreset.js index f37a9155e1d71..4e25ef0188009 100644 --- a/superset-frontend/src/visualizations/presets/MainPreset.js +++ b/superset-frontend/src/visualizations/presets/MainPreset.js @@ -30,7 +30,6 @@ import ParallelCoordinatesChartPlugin from '@superset-ui/legacy-plugin-chart-par import PartitionChartPlugin from '@superset-ui/legacy-plugin-chart-partition'; import RoseChartPlugin from '@superset-ui/legacy-plugin-chart-rose'; import SankeyChartPlugin from '@superset-ui/legacy-plugin-chart-sankey'; -import SunburstChartPlugin from '@superset-ui/legacy-plugin-chart-sunburst'; import TableChartPlugin from '@superset-ui/plugin-chart-table'; import { WordCloudChartPlugin } from '@superset-ui/plugin-chart-word-cloud'; import WorldMapChartPlugin from '@superset-ui/legacy-plugin-chart-world-map'; @@ -127,7 +126,6 @@ export default class MainPreset extends Preset { new PivotTableChartPluginV2().configure({ key: 'pivot_table_v2' }), new RoseChartPlugin().configure({ key: 'rose' }), new SankeyChartPlugin().configure({ key: 'sankey' }), - new SunburstChartPlugin().configure({ key: 'sunburst' }), new TableChartPlugin().configure({ key: 'table' }), new TimePivotChartPlugin().configure({ key: 'time_pivot' }), new TimeTableChartPlugin().configure({ key: 'time_table' }), diff --git a/superset/cachekeys/api.py b/superset/cachekeys/api.py index 9efc3d4c7a27e..40d3830e8bbbb 100644 --- a/superset/cachekeys/api.py +++ b/superset/cachekeys/api.py @@ -84,7 +84,6 @@ def invalidate(self) -> Response: datasource_uids = set(datasources.get("datasource_uids", [])) for ds in datasources.get("datasources", []): ds_obj = SqlaTable.get_datasource_by_name( - session=db.session, datasource_name=ds.get("datasource_name"), schema=ds.get("schema"), database_name=ds.get("database_name"), diff --git a/superset/charts/api.py b/superset/charts/api.py index 191f09c66e7b4..436dffe615c1c 100644 --- a/superset/charts/api.py +++ b/superset/charts/api.py @@ -159,6 +159,7 @@ def ensure_thumbnails_enabled(self) -> Optional[Response]: "cache_timeout", "changed_by.first_name", "changed_by.last_name", + "changed_by.id", "changed_by_name", "changed_on_delta_humanized", "changed_on_dttm", diff --git a/superset/commands/chart/delete.py b/superset/commands/chart/delete.py index ee635f04af99a..abd343125b4ec 100644 --- a/superset/commands/chart/delete.py +++ b/superset/commands/chart/delete.py @@ -31,7 +31,6 @@ from superset.daos.exceptions import DAODeleteFailedError from superset.daos.report import ReportScheduleDAO from superset.exceptions import SupersetSecurityException -from superset.models.dashboard import Dashboard from superset.models.slice import Slice logger = logging.getLogger(__name__) @@ -46,9 +45,6 @@ def run(self) -> None: self.validate() assert self._models - for model_id in self._model_ids: - Dashboard.clear_cache_for_slice(slice_id=model_id) - try: ChartDAO.delete(self._models) except DAODeleteFailedError as ex: diff --git a/superset/commands/dashboard/importers/v0.py b/superset/commands/dashboard/importers/v0.py index 4c2a18e5cc694..bd7aaa4c90381 100644 --- a/superset/commands/dashboard/importers/v0.py +++ b/superset/commands/dashboard/importers/v0.py @@ -22,7 +22,7 @@ from typing import Any, Optional from flask_babel import lazy_gettext as _ -from sqlalchemy.orm import make_transient, Session +from sqlalchemy.orm import make_transient from superset import db from superset.commands.base import BaseCommand @@ -55,7 +55,6 @@ def import_chart( :returns: The resulting id for the imported slice :rtype: int """ - session = db.session make_transient(slc_to_import) slc_to_import.dashboards = [] slc_to_import.alter_params(remote_id=slc_to_import.id, import_time=import_time) @@ -64,7 +63,6 @@ def import_chart( slc_to_import.reset_ownership() params = slc_to_import.params_dict datasource = SqlaTable.get_datasource_by_name( - session=session, datasource_name=params["datasource_name"], database_name=params["database_name"], schema=params["schema"], @@ -72,11 +70,11 @@ def import_chart( slc_to_import.datasource_id = datasource.id # type: ignore if slc_to_override: slc_to_override.override(slc_to_import) - session.flush() + db.session.flush() return slc_to_override.id - session.add(slc_to_import) + db.session.add(slc_to_import) logger.info("Final slice: %s", str(slc_to_import.to_json())) - session.flush() + db.session.flush() return slc_to_import.id @@ -156,7 +154,6 @@ def alter_native_filters(dashboard: Dashboard) -> None: dashboard.json_metadata = json.dumps(json_metadata) logger.info("Started import of the dashboard: %s", dashboard_to_import.to_json()) - session = db.session logger.info("Dashboard has %d slices", len(dashboard_to_import.slices)) # copy slices object as Slice.import_slice will mutate the slice # and will remove the existing dashboard - slice association @@ -173,7 +170,7 @@ def alter_native_filters(dashboard: Dashboard) -> None: i_params_dict = dashboard_to_import.params_dict remote_id_slice_map = { slc.params_dict["remote_id"]: slc - for slc in session.query(Slice).all() + for slc in db.session.query(Slice).all() if "remote_id" in slc.params_dict } for slc in slices: @@ -224,7 +221,7 @@ def alter_native_filters(dashboard: Dashboard) -> None: # override the dashboard existing_dashboard = None - for dash in session.query(Dashboard).all(): + for dash in db.session.query(Dashboard).all(): if ( "remote_id" in dash.params_dict and dash.params_dict["remote_id"] == dashboard_to_import.id @@ -253,18 +250,20 @@ def alter_native_filters(dashboard: Dashboard) -> None: alter_native_filters(dashboard_to_import) new_slices = ( - session.query(Slice).filter(Slice.id.in_(old_to_new_slc_id_dict.values())).all() + db.session.query(Slice) + .filter(Slice.id.in_(old_to_new_slc_id_dict.values())) + .all() ) if existing_dashboard: existing_dashboard.override(dashboard_to_import) existing_dashboard.slices = new_slices - session.flush() + db.session.flush() return existing_dashboard.id dashboard_to_import.slices = new_slices - session.add(dashboard_to_import) - session.flush() + db.session.add(dashboard_to_import) + db.session.flush() return dashboard_to_import.id # type: ignore @@ -291,7 +290,6 @@ def decode_dashboards(o: dict[str, Any]) -> Any: def import_dashboards( - session: Session, content: str, database_id: Optional[int] = None, import_time: Optional[int] = None, @@ -308,10 +306,10 @@ def import_dashboards( params = json.loads(table.params) dataset_id_mapping[params["remote_id"]] = new_dataset_id - session.commit() + db.session.commit() for dashboard in data["dashboards"]: import_dashboard(dashboard, dataset_id_mapping, import_time=import_time) - session.commit() + db.session.commit() class ImportDashboardsCommand(BaseCommand): @@ -334,7 +332,7 @@ def run(self) -> None: for file_name, content in self.contents.items(): logger.info("Importing dashboard from file %s", file_name) - import_dashboards(db.session, content, self.database_id) + import_dashboards(content, self.database_id) def validate(self) -> None: # ensure all files are JSON diff --git a/superset/commands/dataset/create.py b/superset/commands/dataset/create.py index 1c354e835f8a2..16b87a567a5f0 100644 --- a/superset/commands/dataset/create.py +++ b/superset/commands/dataset/create.py @@ -25,13 +25,15 @@ from superset.commands.dataset.exceptions import ( DatabaseNotFoundValidationError, DatasetCreateFailedError, + DatasetDataAccessIsNotAllowed, DatasetExistsValidationError, DatasetInvalidError, TableNotFoundValidationError, ) from superset.daos.dataset import DatasetDAO from superset.daos.exceptions import DAOCreateFailedError -from superset.extensions import db +from superset.exceptions import SupersetSecurityException +from superset.extensions import db, security_manager logger = logging.getLogger(__name__) @@ -82,6 +84,15 @@ def validate(self) -> None: ): exceptions.append(TableNotFoundValidationError(table_name)) + if sql: + try: + security_manager.raise_for_access( + database=database, + sql=sql, + schema=schema, + ) + except SupersetSecurityException as ex: + exceptions.append(DatasetDataAccessIsNotAllowed(ex.error.message)) try: owners = self.populate_owners(owner_ids) self._properties["owners"] = owners diff --git a/superset/commands/dataset/exceptions.py b/superset/commands/dataset/exceptions.py index f135294980835..4b8acaca08b8d 100644 --- a/superset/commands/dataset/exceptions.py +++ b/superset/commands/dataset/exceptions.py @@ -144,6 +144,13 @@ def __init__(self) -> None: super().__init__([_("Owners are invalid")], field_name="owners") +class DatasetDataAccessIsNotAllowed(ValidationError): + status = 422 + + def __init__(self, message: str) -> None: + super().__init__([_(message)], field_name="sql") + + class DatasetNotFoundError(CommandException): status = 404 message = _("Dataset does not exist") diff --git a/superset/commands/explore/get.py b/superset/commands/explore/get.py index bb8f5a85e9e8a..9d715bd63dc5f 100644 --- a/superset/commands/explore/get.py +++ b/superset/commands/explore/get.py @@ -24,7 +24,6 @@ from flask_babel import lazy_gettext as _ from sqlalchemy.exc import SQLAlchemyError -from superset import db from superset.commands.base import BaseCommand from superset.commands.explore.form_data.get import GetFormDataCommand from superset.commands.explore.form_data.parameters import ( @@ -114,7 +113,7 @@ def run(self) -> Optional[dict[str, Any]]: if self._datasource_id is not None: with contextlib.suppress(DatasourceNotFound): datasource = DatasourceDAO.get_datasource( - db.session, cast(str, self._datasource_type), self._datasource_id + cast(str, self._datasource_type), self._datasource_id ) datasource_name = datasource.name if datasource else _("[Missing Dataset]") viz_type = form_data.get("viz_type") diff --git a/superset/commands/utils.py b/superset/commands/utils.py index 8cfeab3c1148d..b7121ec89f0e7 100644 --- a/superset/commands/utils.py +++ b/superset/commands/utils.py @@ -29,7 +29,6 @@ ) from superset.daos.datasource import DatasourceDAO from superset.daos.exceptions import DatasourceNotFound -from superset.extensions import db from superset.utils.core import DatasourceType, get_user_id if TYPE_CHECKING: @@ -80,7 +79,7 @@ def populate_roles(role_ids: list[int] | None = None) -> list[Role]: def get_datasource_by_id(datasource_id: int, datasource_type: str) -> BaseDatasource: try: return DatasourceDAO.get_datasource( - db.session, DatasourceType(datasource_type), datasource_id + DatasourceType(datasource_type), datasource_id ) except DatasourceNotFound as ex: raise DatasourceNotFoundValidationError() from ex diff --git a/superset/common/query_context_factory.py b/superset/common/query_context_factory.py index 708907d4a91ab..fd18b8f90a10f 100644 --- a/superset/common/query_context_factory.py +++ b/superset/common/query_context_factory.py @@ -18,7 +18,7 @@ from typing import Any, TYPE_CHECKING -from superset import app, db +from superset import app from superset.common.chart_data import ChartDataResultFormat, ChartDataResultType from superset.common.query_context import QueryContext from superset.common.query_object import QueryObject @@ -35,7 +35,7 @@ def create_query_object_factory() -> QueryObjectFactory: - return QueryObjectFactory(config, DatasourceDAO(), db.session) + return QueryObjectFactory(config, DatasourceDAO()) class QueryContextFactory: # pylint: disable=too-few-public-methods @@ -95,7 +95,6 @@ def create( def _convert_to_model(self, datasource: DatasourceDict) -> BaseDatasource: return DatasourceDAO.get_datasource( - session=db.session, datasource_type=DatasourceType(datasource["type"]), datasource_id=int(datasource["id"]), ) diff --git a/superset/common/query_object_factory.py b/superset/common/query_object_factory.py index d2aa140dfe933..fe4cca3f4889c 100644 --- a/superset/common/query_object_factory.py +++ b/superset/common/query_object_factory.py @@ -33,8 +33,6 @@ ) if TYPE_CHECKING: - from sqlalchemy.orm import sessionmaker - from superset.connectors.sqla.models import BaseDatasource from superset.daos.datasource import DatasourceDAO @@ -42,17 +40,14 @@ class QueryObjectFactory: # pylint: disable=too-few-public-methods _config: dict[str, Any] _datasource_dao: DatasourceDAO - _session_maker: sessionmaker def __init__( self, app_configurations: dict[str, Any], _datasource_dao: DatasourceDAO, - session_maker: sessionmaker, ): self._config = app_configurations self._datasource_dao = _datasource_dao - self._session_maker = session_maker def create( # pylint: disable=too-many-arguments self, @@ -91,7 +86,6 @@ def _convert_to_model(self, datasource: DatasourceDict) -> BaseDatasource: return self._datasource_dao.get_datasource( datasource_type=DatasourceType(datasource["type"]), datasource_id=int(datasource["id"]), - session=self._session_maker(), ) def _process_extras( diff --git a/superset/config.py b/superset/config.py index 219823b54d1b6..5a103d52ef844 100644 --- a/superset/config.py +++ b/superset/config.py @@ -413,21 +413,12 @@ class D3Format(TypedDict, total=False): # editor no longer shows. Currently this is set to false so that the editor # option does show, but we will be depreciating it. "DISABLE_LEGACY_DATASOURCE_EDITOR": True, - # For some security concerns, you may need to enforce CSRF protection on - # all query request to explore_json endpoint. In Superset, we use - # `flask-csrf `_ add csrf protection - # for all POST requests, but this protection doesn't apply to GET method. - # When ENABLE_EXPLORE_JSON_CSRF_PROTECTION is set to true, your users cannot - # make GET request to explore_json. explore_json accepts both GET and POST request. - # See `PR 7935 `_ for more details. - "ENABLE_EXPLORE_JSON_CSRF_PROTECTION": False, # deprecated "ENABLE_TEMPLATE_PROCESSING": False, - "ENABLE_TEMPLATE_REMOVE_FILTERS": True, # deprecated # Allow for javascript controls components # this enables programmers to customize certain charts (like the # geospatial ones) by inputting javascript in controls. This exposes # an XSS security vulnerability - "ENABLE_JAVASCRIPT_CONTROLS": False, + "ENABLE_JAVASCRIPT_CONTROLS": False, # deprecated "KV_STORE": False, # deprecated # When this feature is enabled, nested types in Presto will be # expanded into extra columns and/or arrays. This is experimental, @@ -435,7 +426,6 @@ class D3Format(TypedDict, total=False): "PRESTO_EXPAND_DATA": False, # Exposes API endpoint to compute thumbnails "THUMBNAILS": False, - "REMOVE_SLICE_LEVEL_LABEL_COLORS": False, # deprecated "SHARE_QUERIES_VIA_KV_STORE": False, "TAGGING_SYSTEM": False, "SQLLAB_BACKEND_PERSISTENCE": True, @@ -443,9 +433,9 @@ class D3Format(TypedDict, total=False): # When True, this escapes HTML (rather than rendering it) in Markdown components "ESCAPE_MARKDOWN_HTML": False, "DASHBOARD_NATIVE_FILTERS": True, # deprecated - "DASHBOARD_CROSS_FILTERS": True, + "DASHBOARD_CROSS_FILTERS": True, # deprecated "DASHBOARD_FILTERS_EXPERIMENTAL": False, # deprecated - "DASHBOARD_VIRTUALIZATION": False, + "DASHBOARD_VIRTUALIZATION": True, "GLOBAL_ASYNC_QUERIES": False, "VERSIONED_EXPORT": True, # deprecated "EMBEDDED_SUPERSET": False, @@ -477,7 +467,7 @@ class D3Format(TypedDict, total=False): # Enable sharing charts with embedding "EMBEDDABLE_CHARTS": True, "DRILL_TO_DETAIL": True, - "DRILL_BY": False, + "DRILL_BY": True, "DATAPANEL_CLOSED_BY_DEFAULT": False, "HORIZONTAL_FILTER_BAR": False, # The feature is off by default, and currently only supported in Presto and Postgres, diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py index 55abaaf68bf07..624eb2ce5a530 100644 --- a/superset/connectors/sqla/models.py +++ b/superset/connectors/sqla/models.py @@ -699,7 +699,7 @@ def raise_for_access(self) -> None: @classmethod def get_datasource_by_name( - cls, session: Session, datasource_name: str, schema: str, database_name: str + cls, datasource_name: str, schema: str, database_name: str ) -> BaseDatasource | None: raise NotImplementedError() @@ -1238,14 +1238,13 @@ def database_name(self) -> str: @classmethod def get_datasource_by_name( cls, - session: Session, datasource_name: str, schema: str | None, database_name: str, ) -> SqlaTable | None: schema = schema or None query = ( - session.query(cls) + db.session.query(cls) .join(Database) .filter(cls.table_name == datasource_name) .filter(Database.database_name == database_name) @@ -1939,12 +1938,10 @@ def query_datasources_by_permissions( # pylint: disable=invalid-name ) @classmethod - def get_eager_sqlatable_datasource( - cls, session: Session, datasource_id: int - ) -> SqlaTable: + def get_eager_sqlatable_datasource(cls, datasource_id: int) -> SqlaTable: """Returns SqlaTable with columns and metrics.""" return ( - session.query(cls) + db.session.query(cls) .options( sa.orm.subqueryload(cls.columns), sa.orm.subqueryload(cls.metrics), @@ -2037,8 +2034,7 @@ def update_column( # pylint: disable=unused-argument :param connection: Unused. :param target: The metric or column that was updated. """ - inspector = inspect(target) - session = inspector.session + session = inspect(target).session # Forces an update to the table's changed_on value when a metric or column on the # table is updated. This busts the cache key for all charts that use the table. diff --git a/superset/daos/dashboard.py b/superset/daos/dashboard.py index e0dffa73c3f64..eef46362e2d9a 100644 --- a/superset/daos/dashboard.py +++ b/superset/daos/dashboard.py @@ -170,7 +170,7 @@ def validate_update_slug_uniqueness(dashboard_id: int, slug: str | None) -> bool return True @staticmethod - def set_dash_metadata( # pylint: disable=too-many-locals + def set_dash_metadata( dashboard: Dashboard, data: dict[Any, Any], old_to_new_slice_ids: dict[int, int] | None = None, @@ -187,8 +187,9 @@ def set_dash_metadata( # pylint: disable=too-many-locals if isinstance(value, dict) ] - session = db.session() - current_slices = session.query(Slice).filter(Slice.id.in_(slice_ids)).all() + current_slices = ( + db.session.query(Slice).filter(Slice.id.in_(slice_ids)).all() + ) dashboard.slices = current_slices diff --git a/superset/daos/datasource.py b/superset/daos/datasource.py index 2bdf4ca21fb7a..0e6058d6abc88 100644 --- a/superset/daos/datasource.py +++ b/superset/daos/datasource.py @@ -18,8 +18,7 @@ import logging from typing import Union -from sqlalchemy.orm import Session - +from superset import db from superset.connectors.sqla.models import SqlaTable from superset.daos.base import BaseDAO from superset.daos.exceptions import DatasourceNotFound, DatasourceTypeNotSupportedError @@ -45,7 +44,6 @@ class DatasourceDAO(BaseDAO[Datasource]): @classmethod def get_datasource( cls, - session: Session, datasource_type: Union[DatasourceType, str], datasource_id: int, ) -> Datasource: @@ -53,7 +51,7 @@ def get_datasource( raise DatasourceTypeNotSupportedError() datasource = ( - session.query(cls.sources[datasource_type]) + db.session.query(cls.sources[datasource_type]) .filter_by(id=datasource_id) .one_or_none() ) diff --git a/superset/dashboards/api.py b/superset/dashboards/api.py index 25570e91bfd96..783543e45de8b 100644 --- a/superset/dashboards/api.py +++ b/superset/dashboards/api.py @@ -438,14 +438,6 @@ def get_charts(self, id_or_slug: str) -> Response: try: charts = DashboardDAO.get_charts_for_dashboard(id_or_slug) result = [self.chart_entity_response_schema.dump(chart) for chart in charts] - - if is_feature_enabled("REMOVE_SLICE_LEVEL_LABEL_COLORS"): - # dashboard metadata has dashboard-level label_colors, - # so remove slice-level label_colors from its form_data - for chart in result: - form_data = chart.get("form_data") - form_data.pop("label_colors", None) - return self.response(200, result=result) except DashboardAccessDeniedError: return self.response_403() diff --git a/superset/datasets/api.py b/superset/datasets/api.py index bc4a42e58ee7e..809074e10ddb2 100644 --- a/superset/datasets/api.py +++ b/superset/datasets/api.py @@ -108,6 +108,7 @@ class DatasetRestApi(BaseSupersetModelRestApi): "changed_by_name", "changed_by.first_name", "changed_by.last_name", + "changed_by.id", "changed_on_utc", "changed_on_delta_humanized", "default_endpoint", diff --git a/superset/datasource/api.py b/superset/datasource/api.py index 6943d00bc75ec..31e8c503ee0fd 100644 --- a/superset/datasource/api.py +++ b/superset/datasource/api.py @@ -18,7 +18,7 @@ from flask_appbuilder.api import expose, protect, safe -from superset import app, db, event_logger +from superset import app, event_logger from superset.daos.datasource import DatasourceDAO from superset.daos.exceptions import DatasourceNotFound, DatasourceTypeNotSupportedError from superset.exceptions import SupersetSecurityException @@ -100,7 +100,7 @@ def get_column_values( """ try: datasource = DatasourceDAO.get_datasource( - db.session, DatasourceType(datasource_type), datasource_id + DatasourceType(datasource_type), datasource_id ) datasource.raise_for_access() except ValueError: diff --git a/superset/db_engine_specs/exceptions.py b/superset/db_engine_specs/exceptions.py index 56e354d62a574..93a6b99271d03 100644 --- a/superset/db_engine_specs/exceptions.py +++ b/superset/db_engine_specs/exceptions.py @@ -38,4 +38,4 @@ class SupersetDBAPIOperationalError(SupersetDBAPIError): class SupersetDBAPIProgrammingError(SupersetDBAPIError): - pass + status = 400 diff --git a/superset/db_engine_specs/trino.py b/superset/db_engine_specs/trino.py index 6bdeae9d7fcea..6d95f9589e49a 100644 --- a/superset/db_engine_specs/trino.py +++ b/superset/db_engine_specs/trino.py @@ -32,7 +32,12 @@ from superset.constants import QUERY_CANCEL_KEY, QUERY_EARLY_CANCEL_KEY, USER_AGENT from superset.databases.utils import make_url_safe from superset.db_engine_specs.base import BaseEngineSpec -from superset.db_engine_specs.exceptions import SupersetDBAPIConnectionError +from superset.db_engine_specs.exceptions import ( + SupersetDBAPIConnectionError, + SupersetDBAPIDatabaseError, + SupersetDBAPIOperationalError, + SupersetDBAPIProgrammingError, +) from superset.db_engine_specs.presto import PrestoBaseEngineSpec from superset.models.sql_lab import Query from superset.superset_typing import ResultSetColumnType @@ -328,11 +333,28 @@ def update_params_from_encrypted_extra( def get_dbapi_exception_mapping(cls) -> dict[type[Exception], type[Exception]]: # pylint: disable=import-outside-toplevel from requests import exceptions as requests_exceptions + from trino import exceptions as trino_exceptions - return { + static_mapping: dict[type[Exception], type[Exception]] = { requests_exceptions.ConnectionError: SupersetDBAPIConnectionError, } + class _CustomMapping(dict[type[Exception], type[Exception]]): + def get( # type: ignore[override] + self, item: type[Exception], default: type[Exception] | None = None + ) -> type[Exception] | None: + if static := static_mapping.get(item): + return static + if issubclass(item, trino_exceptions.InternalError): + return SupersetDBAPIDatabaseError + if issubclass(item, trino_exceptions.OperationalError): + return SupersetDBAPIOperationalError + if issubclass(item, trino_exceptions.ProgrammingError): + return SupersetDBAPIProgrammingError + return default + + return _CustomMapping() + @classmethod def _expand_columns(cls, col: ResultSetColumnType) -> list[ResultSetColumnType]: """ diff --git a/superset/examples/configs/charts/Vaccine_Candidates_per_Country__Stage.yaml b/superset/examples/configs/charts/Vaccine_Candidates_per_Country__Stage.yaml index 81c54e69e33a0..ea9d4c67ef28f 100644 --- a/superset/examples/configs/charts/Vaccine_Candidates_per_Country__Stage.yaml +++ b/superset/examples/configs/charts/Vaccine_Candidates_per_Country__Stage.yaml @@ -15,14 +15,14 @@ # specific language governing permissions and limitations # under the License. slice_name: Vaccine Candidates per Country & Stage -viz_type: sunburst +viz_type: sunburst_v2 params: adhoc_filters: [] color_scheme: supersetColors datasource: 69__table - groupby: - - product_category - - clinical_stage + columns: + - product_category + - clinical_stage linear_color_scheme: schemeYlOrBr metric: count queryFields: @@ -33,7 +33,7 @@ params: slice_id: 3964 time_range: No filter url_params: {} - viz_type: sunburst + viz_type: sunburst_v2 cache_timeout: null uuid: f69c556f-15fe-4a82-a8bb-69d5b6954123 version: 1.0.0 diff --git a/superset/examples/supported_charts_dashboard.py b/superset/examples/supported_charts_dashboard.py index 7354b369bb9a2..926750ffba5f2 100644 --- a/superset/examples/supported_charts_dashboard.py +++ b/superset/examples/supported_charts_dashboard.py @@ -397,12 +397,12 @@ def create_slices(tbl: SqlaTable) -> list[Slice]: Slice( **slice_kwargs, slice_name="Sunburst Chart", - viz_type="sunburst", + viz_type="sunburst_v2", params=get_slice_json( defaults, - viz_type="sunburst", + viz_type="sunburst_v2", metric="sum__num", - groupby=["gender", "state"], + columns=["gender", "state"], ), ), Slice( diff --git a/superset/examples/world_bank.py b/superset/examples/world_bank.py index 1541e3e4724a1..5e895fd78af95 100644 --- a/superset/examples/world_bank.py +++ b/superset/examples/world_bank.py @@ -266,13 +266,13 @@ def create_slices(tbl: BaseDatasource) -> list[Slice]: ), Slice( slice_name="Rural Breakdown", - viz_type="sunburst", + viz_type="sunburst_v2", datasource_type=DatasourceType.TABLE, datasource_id=tbl.id, params=get_slice_json( defaults, - viz_type="sunburst", - groupby=["region", "country_name"], + viz_type="sunburst_v2", + columns=["region", "country_name"], since="2011-01-01", until="2011-01-02", metric=metric, diff --git a/superset/migrations/versions/2024-01-18_14-41_a32e0c4d8646_migrate_sunburst_chart.py b/superset/migrations/versions/2024-01-18_14-41_a32e0c4d8646_migrate_sunburst_chart.py new file mode 100644 index 0000000000000..10644e4073fa6 --- /dev/null +++ b/superset/migrations/versions/2024-01-18_14-41_a32e0c4d8646_migrate_sunburst_chart.py @@ -0,0 +1,44 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""migrate-sunburst-chart + +Revision ID: a32e0c4d8646 +Revises: 59a1450b3c10 +Create Date: 2023-12-22 14:41:43.638321 + +""" + +# revision identifiers, used by Alembic. +revision = "a32e0c4d8646" +down_revision = "59a1450b3c10" + +from alembic import op + +from superset import db +from superset.migrations.shared.migrate_viz import MigrateSunburst + + +def upgrade(): + bind = op.get_bind() + session = db.Session(bind=bind) + MigrateSunburst.upgrade(session) + + +def downgrade(): + bind = op.get_bind() + session = db.Session(bind=bind) + MigrateSunburst.downgrade(session) diff --git a/superset/models/dashboard.py b/superset/models/dashboard.py index 48ee403c4841a..ef346dbd626a9 100644 --- a/superset/models/dashboard.py +++ b/superset/models/dashboard.py @@ -39,15 +39,13 @@ UniqueConstraint, ) from sqlalchemy.engine.base import Connection -from sqlalchemy.orm import relationship, sessionmaker, subqueryload +from sqlalchemy.orm import relationship, subqueryload from sqlalchemy.orm.mapper import Mapper -from sqlalchemy.sql import join, select from sqlalchemy.sql.elements import BinaryExpression from superset import app, db, is_feature_enabled, security_manager from superset.connectors.sqla.models import BaseDatasource, SqlaTable from superset.daos.datasource import DatasourceDAO -from superset.extensions import cache_manager from superset.models.helpers import AuditMixinNullable, ImportExportMixin from superset.models.slice import Slice from superset.models.user_attributes import UserAttribute @@ -55,45 +53,39 @@ from superset.tasks.utils import get_current_user from superset.thumbnails.digest import get_dashboard_digest from superset.utils import core as utils -from superset.utils.decorators import debounce metadata = Model.metadata # pylint: disable=no-member config = app.config logger = logging.getLogger(__name__) -def copy_dashboard(_mapper: Mapper, connection: Connection, target: Dashboard) -> None: +def copy_dashboard(_mapper: Mapper, _connection: Connection, target: Dashboard) -> None: dashboard_id = config["DASHBOARD_TEMPLATE_ID"] if dashboard_id is None: return - session_class = sessionmaker(autoflush=False) - session = session_class(bind=connection) - - try: - new_user = session.query(User).filter_by(id=target.id).first() - - # copy template dashboard to user - template = session.query(Dashboard).filter_by(id=int(dashboard_id)).first() - dashboard = Dashboard( - dashboard_title=template.dashboard_title, - position_json=template.position_json, - description=template.description, - css=template.css, - json_metadata=template.json_metadata, - slices=template.slices, - owners=[new_user], - ) - session.add(dashboard) + session = sqla.inspect(target).session + new_user = session.query(User).filter_by(id=target.id).first() + + # copy template dashboard to user + template = session.query(Dashboard).filter_by(id=int(dashboard_id)).first() + dashboard = Dashboard( + dashboard_title=template.dashboard_title, + position_json=template.position_json, + description=template.description, + css=template.css, + json_metadata=template.json_metadata, + slices=template.slices, + owners=[new_user], + ) + session.add(dashboard) - # set dashboard as the welcome dashboard - extra_attributes = UserAttribute( - user_id=target.id, welcome_dashboard_id=dashboard.id - ) - session.add(extra_attributes) - session.commit() - finally: - session.close() + # set dashboard as the welcome dashboard + extra_attributes = UserAttribute( + user_id=target.id, welcome_dashboard_id=dashboard.id + ) + session.add(extra_attributes) + session.commit() sqla.event.listen(User, "after_insert", copy_dashboard) @@ -137,7 +129,6 @@ def copy_dashboard(_mapper: Mapper, connection: Connection, target: Dashboard) - ) -# pylint: disable=too-many-public-methods class Dashboard(AuditMixinNullable, ImportExportMixin, Model): """The dashboard object!""" @@ -322,36 +313,6 @@ def update_thumbnail(self) -> None: force=True, ) - @debounce(0.1) - def clear_cache(self) -> None: - cache_manager.cache.delete_memoized(Dashboard.datasets_trimmed_for_slices, self) - - @classmethod - @debounce(0.1) - def clear_cache_for_slice(cls, slice_id: int) -> None: - filter_query = select([dashboard_slices.c.dashboard_id], distinct=True).where( - dashboard_slices.c.slice_id == slice_id - ) - for (dashboard_id,) in db.engine.execute(filter_query): - cls(id=dashboard_id).clear_cache() - - @classmethod - @debounce(0.1) - def clear_cache_for_datasource(cls, datasource_id: int) -> None: - filter_query = select( - [dashboard_slices.c.dashboard_id], - distinct=True, - ).select_from( - join( - dashboard_slices, - Slice, - (Slice.id == dashboard_slices.c.slice_id) - & (Slice.datasource_id == datasource_id), - ) - ) - for (dashboard_id,) in db.engine.execute(filter_query): - cls(id=dashboard_id).clear_cache() - @classmethod def export_dashboards( # pylint: disable=too-many-locals cls, @@ -397,7 +358,7 @@ def export_dashboards( # pylint: disable=too-many-locals if id_ is None: continue datasource = DatasourceDAO.get_datasource( - db.session, utils.DatasourceType.TABLE, id_ + utils.DatasourceType.TABLE, id_ ) datasource_ids.add((datasource.id, datasource.type)) @@ -406,9 +367,7 @@ def export_dashboards( # pylint: disable=too-many-locals eager_datasources = [] for datasource_id, _ in datasource_ids: - eager_datasource = SqlaTable.get_eager_sqlatable_datasource( - db.session, datasource_id - ) + eager_datasource = SqlaTable.get_eager_sqlatable_datasource(datasource_id) copied_datasource = eager_datasource.copy() copied_datasource.alter_params( remote_id=eager_datasource.id, diff --git a/superset/models/helpers.py b/superset/models/helpers.py index d64b9036a49be..2c56c41b904df 100644 --- a/superset/models/helpers.py +++ b/superset/models/helpers.py @@ -1760,10 +1760,9 @@ def get_sqla_query( # pylint: disable=too-many-arguments,too-many-locals,too-ma col_obj = columns_by_name.get(cast(str, flt_col)) filter_grain = flt.get("grain") - if is_feature_enabled("ENABLE_TEMPLATE_REMOVE_FILTERS"): - if get_column_name(flt_col) in removed_filters: - # Skip generating SQLA filter when the jinja template handles it. - continue + if get_column_name(flt_col) in removed_filters: + # Skip generating SQLA filter when the jinja template handles it. + continue if col_obj or sqla_col is not None: if sqla_col is not None: diff --git a/superset/security/manager.py b/superset/security/manager.py index 5eb1afdda99a2..618a7e2808a46 100644 --- a/superset/security/manager.py +++ b/superset/security/manager.py @@ -48,7 +48,7 @@ from jwt.api_jwt import _jwt_global_obj from sqlalchemy import and_, inspect, or_ from sqlalchemy.engine.base import Connection -from sqlalchemy.orm import eagerload, Session +from sqlalchemy.orm import eagerload from sqlalchemy.orm.mapper import Mapper from sqlalchemy.orm.query import Query as SqlaQuery @@ -545,8 +545,7 @@ def get_user_datasources(self) -> list["BaseDatasource"]: ) # group all datasources by database - session = self.get_session - all_datasources = SqlaTable.get_all_datasources(session) + all_datasources = SqlaTable.get_all_datasources(self.get_session) datasources_by_database: dict["Database", set["SqlaTable"]] = defaultdict(set) for datasource in all_datasources: datasources_by_database[datasource.database].add(datasource) @@ -1828,6 +1827,8 @@ def raise_for_access( query_context: Optional["QueryContext"] = None, table: Optional["Table"] = None, viz: Optional["BaseViz"] = None, + sql: Optional[str] = None, + schema: Optional[str] = None, ) -> None: """ Raise an exception if the user cannot access the resource. @@ -1838,6 +1839,8 @@ def raise_for_access( :param query_context: The query context :param table: The Superset table (requires database) :param viz: The visualization + :param sql: The SQL string (requires database) + :param schema: Optional schema name :raises SupersetSecurityException: If the user cannot access the resource """ @@ -1846,7 +1849,19 @@ def raise_for_access( from superset.connectors.sqla.models import SqlaTable from superset.models.dashboard import Dashboard from superset.models.slice import Slice + from superset.models.sql_lab import Query from superset.sql_parse import Table + from superset.utils.core import shortid + + if sql and database: + query = Query( + database=database, + sql=sql, + schema=schema, + client_id=shortid()[:10], + user_id=get_user_id(), + ) + self.get_session.expunge(query) if database and table or query: if query: @@ -2001,17 +2016,14 @@ def raise_for_access( self.get_dashboard_access_error_object(dashboard) ) - def get_user_by_username( - self, username: str, session: Session = None - ) -> Optional[User]: + def get_user_by_username(self, username: str) -> Optional[User]: """ Retrieves a user by it's username case sensitive. Optional session parameter utility method normally useful for celery tasks where the session need to be scoped """ - session = session or self.get_session return ( - session.query(self.user_model) + self.get_session.query(self.user_model) .filter(self.user_model.username == username) .one_or_none() ) diff --git a/superset/translations/zh/LC_MESSAGES/messages.po b/superset/translations/zh/LC_MESSAGES/messages.po index 791ea2c4db7be..4997d7ab97163 100644 --- a/superset/translations/zh/LC_MESSAGES/messages.po +++ b/superset/translations/zh/LC_MESSAGES/messages.po @@ -19232,7 +19232,7 @@ msgstr "时间序列的列" #: superset-frontend/src/dashboard/components/gridComponents/Tab.jsx:210 #, fuzzy msgid "edit mode" -msgstr "光模式" +msgstr "编辑模式" #: superset-frontend/plugins/plugin-chart-table/src/DataTable/components/SelectPageSize.tsx:58 #, fuzzy @@ -19311,7 +19311,7 @@ msgstr "" msgid "" "filter_box will be deprecated in a future version of Superset. Please " "replace filter_box by dashboard filter components." -msgstr "'filter_box将在Superset的未来版本中弃用。" +msgstr "filter_box将在Superset的未来版本中弃用。" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:219 #: superset-frontend/plugins/plugin-chart-echarts/src/BoxPlot/controlPanel.ts:119 @@ -19322,7 +19322,7 @@ msgstr "在" #: superset-frontend/src/features/databases/DatabaseModal/SqlAlchemyForm.tsx:100 msgid "for more information on how to structure your URI." -msgstr " 来查询有关如何构造URI的更多信息。" +msgstr "来查询有关如何构造URI的更多信息。" #: superset-frontend/packages/superset-ui-chart-controls/src/components/ColumnTypeLabel/ColumnTypeLabel.tsx:57 msgid "function type icon" @@ -19339,7 +19339,7 @@ msgstr "热力图" #: superset-frontend/plugins/legacy-plugin-chart-heatmap/src/controlPanel.tsx:184 msgid "heatmap: values are normalized across the entire heatmap" -msgstr "" +msgstr "热力图:其中所有数值都经过了归一化" #: superset-frontend/src/components/EmptyState/index.tsx:231 #: superset-frontend/src/components/ImportModal/ErrorAlert.tsx:60 @@ -19384,7 +19384,7 @@ msgstr "应该为数字" #: superset-frontend/packages/superset-ui-core/src/validator/legacyValidateInteger.ts:31 #: superset-frontend/packages/superset-ui-core/src/validator/validateInteger.ts:32 msgid "is expected to be an integer" -msgstr "应该为为整数" +msgstr "应该为整数" #: superset-frontend/src/profile/components/UserInfo.tsx:64 msgid "joined" @@ -19477,7 +19477,7 @@ msgstr "最大值" #: superset-frontend/src/explore/controlPanels/sections.tsx:255 #, fuzzy msgid "mean" -msgstr "主域" +msgstr "平均值" #: superset-frontend/plugins/legacy-plugin-chart-partition/src/controlPanel.tsx:376 #: superset-frontend/plugins/legacy-plugin-chart-rose/src/controlPanel.tsx:258 @@ -19485,7 +19485,7 @@ msgstr "主域" #: superset-frontend/plugins/legacy-preset-chart-nvd3/src/NVD3Controls.tsx:530 #: superset-frontend/src/explore/controlPanels/sections.tsx:254 msgid "median" -msgstr "" +msgstr "中位数" #: superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx:62 #: superset-frontend/src/explore/components/controls/FixedOrMetricControl/index.jsx:136 @@ -19499,7 +19499,7 @@ msgstr "指标" #: superset-frontend/src/filters/components/Range/buildQuery.ts:58 #, fuzzy msgid "min" -msgstr "在" +msgstr "分钟" #: superset-frontend/src/components/CronPicker/CronPicker.tsx:41 msgid "minute" diff --git a/superset/utils/database.py b/superset/utils/database.py index b34dda1164a45..073e58ffda6fb 100644 --- a/superset/utils/database.py +++ b/superset/utils/database.py @@ -79,6 +79,5 @@ def remove_database(database: Database) -> None: # pylint: disable=import-outside-toplevel from superset import db - session = db.session - session.delete(database) - session.commit() + db.session.delete(database) + db.session.commit() diff --git a/superset/utils/log.py b/superset/utils/log.py index 5430accb43ac2..1de599bf08233 100644 --- a/superset/utils/log.py +++ b/superset/utils/log.py @@ -27,7 +27,7 @@ from datetime import datetime, timedelta from typing import Any, Callable, cast, Literal, TYPE_CHECKING -from flask import current_app, g, request +from flask import g, request from flask_appbuilder.const import API_URI_RIS_KEY from sqlalchemy.exc import SQLAlchemyError @@ -139,6 +139,7 @@ def log_with_context( # pylint: disable=too-many-locals **payload_override: dict[str, Any] | None, ) -> None: # pylint: disable=import-outside-toplevel + from superset import db from superset.views.core import get_form_data referrer = request.referrer[:1000] if request and request.referrer else None @@ -152,8 +153,7 @@ def log_with_context( # pylint: disable=too-many-locals # need to add them back before logging to capture user_id if user_id is None: try: - session = current_app.appbuilder.get_session - session.add(g.user) + db.session.add(g.user) user_id = get_user_id() except Exception as ex: # pylint: disable=broad-except logging.warning(ex) @@ -332,6 +332,7 @@ def log( # pylint: disable=too-many-arguments,too-many-locals **kwargs: Any, ) -> None: # pylint: disable=import-outside-toplevel + from superset import db from superset.models.core import Log records = kwargs.get("records", []) @@ -353,9 +354,8 @@ def log( # pylint: disable=too-many-arguments,too-many-locals ) logs.append(log) try: - sesh = current_app.appbuilder.get_session - sesh.bulk_save_objects(logs) - sesh.commit() + db.session.bulk_save_objects(logs) + db.session.commit() except SQLAlchemyError as ex: logging.error("DBEventLogger failed to log event(s)") logging.exception(ex) diff --git a/superset/utils/mock_data.py b/superset/utils/mock_data.py index fd4961421585d..67bd9ad73e106 100644 --- a/superset/utils/mock_data.py +++ b/superset/utils/mock_data.py @@ -31,7 +31,6 @@ from flask_appbuilder import Model from sqlalchemy import Column, inspect, MetaData, Table from sqlalchemy.dialects import postgresql -from sqlalchemy.orm import Session from sqlalchemy.sql import func from sqlalchemy.sql.visitors import VisitableType @@ -231,12 +230,10 @@ def generate_column_data(column: ColumnInfo, num_rows: int) -> list[Any]: return [gen() for _ in range(num_rows)] -def add_sample_rows( - session: Session, model: type[Model], count: int -) -> Iterator[Model]: +def add_sample_rows(model: type[Model], count: int) -> Iterator[Model]: """ Add entities of a given model. - :param Session session: an SQLAlchemy session + :param Model model: a Superset/FAB model :param int count: how many entities to generate and insert """ @@ -244,7 +241,7 @@ def add_sample_rows( # select samples to copy relationship values relationships = inspector.relationships.items() - samples = session.query(model).limit(count).all() if relationships else [] + samples = db.session.query(model).limit(count).all() if relationships else [] max_primary_key: Optional[int] = None for i in range(count): @@ -255,7 +252,7 @@ def add_sample_rows( if column.primary_key: if max_primary_key is None: max_primary_key = ( - session.query(func.max(getattr(model, column.name))).scalar() + db.session.query(func.max(getattr(model, column.name))).scalar() or 0 ) max_primary_key += 1 diff --git a/superset/views/core.py b/superset/views/core.py index 9ad2f63fdc680..febebed34bf9f 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. # pylint: disable=invalid-name +# pylint: disable=too-many-lines from __future__ import annotations import contextlib @@ -238,19 +239,24 @@ def explore_json_data(self, cache_key: str) -> FlaskResponse: except SupersetException as ex: return json_error_response(utils.error_msg_from_exception(ex), 400) - EXPLORE_JSON_METHODS = ["POST"] - if not is_feature_enabled("ENABLE_EXPLORE_JSON_CSRF_PROTECTION"): - EXPLORE_JSON_METHODS.append("GET") - @api @has_access_api @handle_api_exception @event_logger.log_this @expose( "/explore_json///", - methods=EXPLORE_JSON_METHODS, + methods=( + "GET", + "POST", + ), + ) + @expose( + "/explore_json/", + methods=( + "GET", + "POST", + ), ) - @expose("/explore_json/", methods=EXPLORE_JSON_METHODS) @etag_cache() @check_resource_permissions(check_datasource_perms) @deprecated(eol_version="4.0.0") @@ -510,7 +516,6 @@ def explore( if datasource_id is not None: with contextlib.suppress(DatasetNotFoundError): datasource = DatasourceDAO.get_datasource( - db.session, DatasourceType("table"), datasource_id, ) @@ -751,7 +756,6 @@ def warm_up_cache(self) -> FlaskResponse: In terms of the `extra_filters` these can be obtained from records in the JSON encoded `logs.json` column associated with the `explore_json` action. """ - session = db.session() slice_id = request.args.get("slice_id") dashboard_id = request.args.get("dashboard_id") table_name = request.args.get("table_name") @@ -768,14 +772,14 @@ def warm_up_cache(self) -> FlaskResponse: status=400, ) if slice_id: - slices = session.query(Slice).filter_by(id=slice_id).all() + slices = db.session.query(Slice).filter_by(id=slice_id).all() if not slices: return json_error_response( __("Chart %(id)s not found", id=slice_id), status=404 ) elif table_name and db_name: table = ( - session.query(SqlaTable) + db.session.query(SqlaTable) .join(Database) .filter( Database.database_name == db_name @@ -792,7 +796,7 @@ def warm_up_cache(self) -> FlaskResponse: status=404, ) slices = ( - session.query(Slice) + db.session.query(Slice) .filter_by(datasource_id=table.id, datasource_type=table.type) .all() ) @@ -919,7 +923,7 @@ def fetch_datasource_metadata(self) -> FlaskResponse: """ datasource_id, datasource_type = request.args["datasourceKey"].split("__") datasource = DatasourceDAO.get_datasource( - db.session, DatasourceType(datasource_type), int(datasource_id) + DatasourceType(datasource_type), int(datasource_id) ) # Check if datasource exists if not datasource: diff --git a/superset/views/datasource/utils.py b/superset/views/datasource/utils.py index b08d1ccc1528d..6bad2370c8758 100644 --- a/superset/views/datasource/utils.py +++ b/superset/views/datasource/utils.py @@ -16,7 +16,7 @@ # under the License. from typing import Any, Optional -from superset import app, db +from superset import app from superset.commands.dataset.exceptions import DatasetSamplesFailedError from superset.common.chart_data import ChartDataResultType from superset.common.query_context_factory import QueryContextFactory @@ -52,7 +52,6 @@ def get_samples( # pylint: disable=too-many-arguments payload: Optional[SamplesPayloadSchema] = None, ) -> dict[str, Any]: datasource = DatasourceDAO.get_datasource( - session=db.session, datasource_type=datasource_type, datasource_id=datasource_id, ) diff --git a/superset/views/datasource/views.py b/superset/views/datasource/views.py index b911d2ea3f116..2e46faf0af9dc 100644 --- a/superset/views/datasource/views.py +++ b/superset/views/datasource/views.py @@ -83,7 +83,7 @@ def save(self) -> FlaskResponse: datasource_type = datasource_dict.get("type") database_id = datasource_dict["database"].get("id") orm_datasource = DatasourceDAO.get_datasource( - db.session, DatasourceType(datasource_type), datasource_id + DatasourceType(datasource_type), datasource_id ) orm_datasource.database_id = database_id @@ -126,7 +126,7 @@ def save(self) -> FlaskResponse: @deprecated(new_target="/api/v1/dataset/") def get(self, datasource_type: str, datasource_id: int) -> FlaskResponse: datasource = DatasourceDAO.get_datasource( - db.session, DatasourceType(datasource_type), datasource_id + DatasourceType(datasource_type), datasource_id ) return self.json_response(sanitize_datasource_data(datasource.data)) @@ -139,7 +139,6 @@ def external_metadata( ) -> FlaskResponse: """Gets column info from the source system""" datasource = DatasourceDAO.get_datasource( - db.session, DatasourceType(datasource_type), datasource_id, ) @@ -164,7 +163,6 @@ def external_metadata_by_name(self, **kwargs: Any) -> FlaskResponse: return json_error_response(str(err), status=400) datasource = SqlaTable.get_datasource_by_name( - session=db.session, database_name=params["database_name"], schema=params["schema_name"], datasource_name=params["table_name"], diff --git a/superset/views/utils.py b/superset/views/utils.py index db5b3b53467f5..574fedb66b7d0 100644 --- a/superset/views/utils.py +++ b/superset/views/utils.py @@ -129,7 +129,6 @@ def get_viz( ) -> BaseViz: viz_type = form_data.get("viz_type", "table") datasource = DatasourceDAO.get_datasource( - db.session, DatasourceType(datasource_type), datasource_id, ) @@ -312,8 +311,7 @@ def apply_display_max_row_limit( def get_dashboard_extra_filters( slice_id: int, dashboard_id: int ) -> list[dict[str, Any]]: - session = db.session() - dashboard = session.query(Dashboard).filter_by(id=dashboard_id).one_or_none() + dashboard = db.session.query(Dashboard).filter_by(id=dashboard_id).one_or_none() # is chart in this dashboard? if ( diff --git a/superset/viz.py b/superset/viz.py index 8ba785ddcf39e..5738fabc939eb 100644 --- a/superset/viz.py +++ b/superset/viz.py @@ -1352,55 +1352,6 @@ def get_data(self, df: pd.DataFrame) -> VizData: # pylint: disable=too-many-loc return chart_data -class SunburstViz(BaseViz): - - """A multi level sunburst chart""" - - viz_type = "sunburst" - verbose_name = _("Sunburst") - is_timeseries = False - credits = ( - "Kerry Rodden " - '@bl.ocks.org' - ) - - @deprecated(deprecated_in="3.0") - def get_data(self, df: pd.DataFrame) -> VizData: - if df.empty: - return None - form_data = copy.deepcopy(self.form_data) - cols = get_column_names(form_data.get("groupby")) - cols.extend(["m1", "m2"]) - metric = utils.get_metric_name(form_data["metric"]) - secondary_metric = ( - utils.get_metric_name(form_data["secondary_metric"]) - if form_data.get("secondary_metric") - else None - ) - if metric == secondary_metric or secondary_metric is None: - df.rename(columns={df.columns[-1]: "m1"}, inplace=True) - df["m2"] = df["m1"] - else: - df.rename(columns={df.columns[-2]: "m1"}, inplace=True) - df.rename(columns={df.columns[-1]: "m2"}, inplace=True) - - # Re-order the columns as the query result set column ordering may differ from - # that listed in the hierarchy. - df = df[cols] - return df.to_numpy().tolist() - - @deprecated(deprecated_in="3.0") - def query_obj(self) -> QueryObjectDict: - query_obj = super().query_obj() - query_obj["metrics"] = [self.form_data["metric"]] - secondary_metric = self.form_data.get("secondary_metric") - if secondary_metric and secondary_metric != self.form_data["metric"]: - query_obj["metrics"].append(secondary_metric) - if self.form_data.get("sort_by_metric", False): - query_obj["orderby"] = [(query_obj["metrics"][0], False)] - return query_obj - - class SankeyViz(BaseViz): """A Sankey diagram that requires a parent-child dataset""" diff --git a/tests/integration_tests/core_tests.py b/tests/integration_tests/core_tests.py index c4a0897332b38..6d1a62c7f2fc8 100644 --- a/tests/integration_tests/core_tests.py +++ b/tests/integration_tests/core_tests.py @@ -559,8 +559,15 @@ def test_comments_in_sqlatable_query(self): self.assertEqual(clean_query, rendered_query) def test_slice_payload_no_datasource(self): + form_data = { + "viz_type": "dist_bar", + } self.login(username="admin") - data = self.get_json_resp("/superset/explore_json/", raise_on_error=False) + rv = self.client.post( + "/superset/explore_json/", + data={"form_data": json.dumps(form_data)}, + ) + data = json.loads(rv.data.decode("utf-8")) self.assertEqual( data["errors"][0]["message"], diff --git a/tests/integration_tests/datasets/commands_tests.py b/tests/integration_tests/datasets/commands_tests.py index 1ea554a81838f..b45bbdb76d5eb 100644 --- a/tests/integration_tests/datasets/commands_tests.py +++ b/tests/integration_tests/datasets/commands_tests.py @@ -38,7 +38,7 @@ from superset.connectors.sqla.models import SqlaTable from superset.models.core import Database from superset.models.slice import Slice -from superset.utils.core import get_example_default_schema +from superset.utils.core import get_example_default_schema, override_user from superset.utils.database import get_example_database from tests.integration_tests.base_tests import SupersetTestCase from tests.integration_tests.fixtures.birth_names_dashboard import ( @@ -509,6 +509,7 @@ def test_import_v1_dataset_existing_database(self, mock_g): "metadata.yaml": yaml.safe_dump(database_metadata_config), "databases/imported_database.yaml": yaml.safe_dump(database_config), } + command = ImportDatabasesCommand(contents) command.run() @@ -558,11 +559,7 @@ def test_get_table_from_database_error(self, get_table_mock): {"table_name": "table", "database": get_example_database().id} ).run() - @patch("superset.security.manager.g") - @patch("superset.commands.utils.g") - def test_create_dataset_command(self, mock_g, mock_g2): - mock_g.user = security_manager.find_user("admin") - mock_g2.user = mock_g.user + def test_create_dataset_command(self): examples_db = get_example_database() with examples_db.get_sqla_engine_with_context() as engine: engine.execute("DROP TABLE IF EXISTS test_create_dataset_command") @@ -570,22 +567,38 @@ def test_create_dataset_command(self, mock_g, mock_g2): "CREATE TABLE test_create_dataset_command AS SELECT 2 as col" ) - table = CreateDatasetCommand( - {"table_name": "test_create_dataset_command", "database": examples_db.id} - ).run() - fetched_table = ( - db.session.query(SqlaTable) - .filter_by(table_name="test_create_dataset_command") - .one() - ) - self.assertEqual(table, fetched_table) - self.assertEqual([owner.username for owner in table.owners], ["admin"]) + with override_user(security_manager.find_user("admin")): + table = CreateDatasetCommand( + { + "table_name": "test_create_dataset_command", + "database": examples_db.id, + } + ).run() + fetched_table = ( + db.session.query(SqlaTable) + .filter_by(table_name="test_create_dataset_command") + .one() + ) + self.assertEqual(table, fetched_table) + self.assertEqual([owner.username for owner in table.owners], ["admin"]) db.session.delete(table) with examples_db.get_sqla_engine_with_context() as engine: engine.execute("DROP TABLE test_create_dataset_command") db.session.commit() + def test_create_dataset_command_not_allowed(self): + examples_db = get_example_database() + with override_user(security_manager.find_user("gamma")): + with self.assertRaises(DatasetInvalidError): + _ = CreateDatasetCommand( + { + "sql": "select * from ab_user", + "database": examples_db.id, + "table_name": "exp1", + } + ).run() + class TestDatasetWarmUpCacheCommand(SupersetTestCase): def test_warm_up_cache_command_table_not_found(self): diff --git a/tests/integration_tests/datasource_tests.py b/tests/integration_tests/datasource_tests.py index 5ab81b58d12cd..dce33ea2ccaea 100644 --- a/tests/integration_tests/datasource_tests.py +++ b/tests/integration_tests/datasource_tests.py @@ -474,7 +474,7 @@ def test_get_datasource_failed(self): pytest.raises( DatasourceNotFound, - lambda: DatasourceDAO.get_datasource(db.session, "table", 9999999), + lambda: DatasourceDAO.get_datasource("table", 9999999), ) self.login(username="admin") @@ -486,7 +486,7 @@ def test_get_datasource_invalid_datasource_failed(self): pytest.raises( DatasourceTypeNotSupportedError, - lambda: DatasourceDAO.get_datasource(db.session, "druid", 9999999), + lambda: DatasourceDAO.get_datasource("druid", 9999999), ) self.login(username="admin") diff --git a/tests/integration_tests/query_context_tests.py b/tests/integration_tests/query_context_tests.py index 30cd160d7ee58..0d6d69e4ce9e7 100644 --- a/tests/integration_tests/query_context_tests.py +++ b/tests/integration_tests/query_context_tests.py @@ -145,7 +145,6 @@ def test_query_cache_key_changes_when_datasource_is_updated(self): # make temporary change and revert it to refresh the changed_on property datasource = DatasourceDAO.get_datasource( - session=db.session, datasource_type=DatasourceType(payload["datasource"]["type"]), datasource_id=payload["datasource"]["id"], ) @@ -169,7 +168,6 @@ def test_query_cache_key_changes_when_metric_is_updated(self): # make temporary change and revert it to refresh the changed_on property datasource = DatasourceDAO.get_datasource( - session=db.session, datasource_type=DatasourceType(payload["datasource"]["type"]), datasource_id=payload["datasource"]["id"], ) diff --git a/tests/integration_tests/security_tests.py b/tests/integration_tests/security_tests.py index 9eaabf3680ec4..c9d2a41057ba3 100644 --- a/tests/integration_tests/security_tests.py +++ b/tests/integration_tests/security_tests.py @@ -43,6 +43,7 @@ DatasourceType, backend, get_example_default_schema, + override_user, ) from superset.utils.database import get_example_database from superset.utils.urls import get_url_host @@ -108,9 +109,8 @@ class TestRolePermission(SupersetTestCase): def setUp(self): schema = get_example_default_schema() - session = db.session security_manager.add_role(SCHEMA_ACCESS_ROLE) - session.commit() + db.session.commit() ds = ( db.session.query(SqlaTable) @@ -121,7 +121,7 @@ def setUp(self): ds.schema_perm = ds.get_schema_perm() ds_slices = ( - session.query(Slice) + db.session.query(Slice) .filter_by(datasource_type=DatasourceType.TABLE) .filter_by(datasource_id=ds.id) .all() @@ -131,12 +131,11 @@ def setUp(self): create_schema_perm("[examples].[temp_schema]") gamma_user = security_manager.find_user(username="gamma") gamma_user.roles.append(security_manager.find_role(SCHEMA_ACCESS_ROLE)) - session.commit() + db.session.commit() def tearDown(self): - session = db.session ds = ( - session.query(SqlaTable) + db.session.query(SqlaTable) .filter_by(table_name="wb_health_population", schema="temp_schema") .first() ) @@ -144,7 +143,7 @@ def tearDown(self): ds.schema = get_example_default_schema() ds.schema_perm = None ds_slices = ( - session.query(Slice) + db.session.query(Slice) .filter_by(datasource_type=DatasourceType.TABLE) .filter_by(datasource_id=ds.id) .all() @@ -153,26 +152,25 @@ def tearDown(self): s.schema_perm = None delete_schema_perm(schema_perm) - session.delete(security_manager.find_role(SCHEMA_ACCESS_ROLE)) - session.commit() + db.session.delete(security_manager.find_role(SCHEMA_ACCESS_ROLE)) + db.session.commit() def test_after_insert_dataset(self): security_manager.on_view_menu_after_insert = Mock() security_manager.on_permission_view_after_insert = Mock() - session = db.session tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") - session.add(tmp_db1) + db.session.add(tmp_db1) table = SqlaTable( schema="tmp_schema", table_name="tmp_perm_table", database=tmp_db1, ) - session.add(table) - session.commit() + db.session.add(table) + db.session.commit() - table = session.query(SqlaTable).filter_by(table_name="tmp_perm_table").one() + table = db.session.query(SqlaTable).filter_by(table_name="tmp_perm_table").one() self.assertEqual(table.perm, f"[tmp_db1].[tmp_perm_table](id:{table.id})") pvm_dataset = security_manager.find_permission_view_menu( @@ -200,54 +198,54 @@ def test_after_insert_dataset(self): ) # Cleanup - session.delete(table) - session.delete(tmp_db1) - session.commit() + db.session.delete(table) + db.session.delete(tmp_db1) + db.session.commit() def test_after_insert_dataset_rollback(self): - session = db.session tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") - session.add(tmp_db1) - session.commit() + db.session.add(tmp_db1) + db.session.commit() table = SqlaTable( schema="tmp_schema", table_name="tmp_table", database=tmp_db1, ) - session.add(table) - session.flush() + db.session.add(table) + db.session.flush() pvm_dataset = security_manager.find_permission_view_menu( "datasource_access", f"[tmp_db1].[tmp_table](id:{table.id})" ) self.assertIsNotNone(pvm_dataset) table_id = table.id - session.rollback() + db.session.rollback() - table = session.query(SqlaTable).filter_by(table_name="tmp_table").one_or_none() + table = ( + db.session.query(SqlaTable).filter_by(table_name="tmp_table").one_or_none() + ) self.assertIsNone(table) pvm_dataset = security_manager.find_permission_view_menu( "datasource_access", f"[tmp_db1].[tmp_table](id:{table_id})" ) self.assertIsNone(pvm_dataset) - session.delete(tmp_db1) - session.commit() + db.session.delete(tmp_db1) + db.session.commit() def test_after_insert_dataset_table_none(self): - session = db.session table = SqlaTable( schema="tmp_schema", table_name="tmp_perm_table", # Setting database_id instead of database will skip permission creation database_id=get_example_database().id, ) - session.add(table) - session.commit() + db.session.add(table) + db.session.commit() stored_table = ( - session.query(SqlaTable).filter_by(table_name="tmp_perm_table").one() + db.session.query(SqlaTable).filter_by(table_name="tmp_perm_table").one() ) # Assert permission is created self.assertIsNotNone( @@ -263,17 +261,16 @@ def test_after_insert_dataset_table_none(self): ) # Cleanup - session.delete(table) - session.commit() + db.session.delete(table) + db.session.commit() def test_after_insert_database(self): security_manager.on_permission_view_after_insert = Mock() - session = db.session tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") - session.add(tmp_db1) + db.session.add(tmp_db1) - tmp_db1 = session.query(Database).filter_by(database_name="tmp_db1").one() + tmp_db1 = db.session.query(Database).filter_by(database_name="tmp_db1").one() self.assertEqual(tmp_db1.perm, f"[tmp_db1].(id:{tmp_db1.id})") tmp_db1_pvm = security_manager.find_permission_view_menu( "database_access", tmp_db1.perm @@ -288,20 +285,19 @@ def test_after_insert_database(self): ) call_args = security_manager.on_permission_view_after_insert.call_args assert call_args.args[2].id == tmp_db1_pvm.id - session.delete(tmp_db1) - session.commit() + db.session.delete(tmp_db1) + db.session.commit() def test_after_insert_database_rollback(self): - session = db.session tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") - session.add(tmp_db1) - session.flush() + db.session.add(tmp_db1) + db.session.flush() pvm_database = security_manager.find_permission_view_menu( "database_access", f"[tmp_db1].(id:{tmp_db1.id})" ) self.assertIsNotNone(pvm_database) - session.rollback() + db.session.rollback() pvm_database = security_manager.find_permission_view_menu( "database_access", f"[tmp_db1](id:{tmp_db1.id})" @@ -311,18 +307,17 @@ def test_after_insert_database_rollback(self): def test_after_update_database__perm_database_access(self): security_manager.on_view_menu_after_update = Mock() - session = db.session tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") - session.add(tmp_db1) - session.commit() - tmp_db1 = session.query(Database).filter_by(database_name="tmp_db1").one() + db.session.add(tmp_db1) + db.session.commit() + tmp_db1 = db.session.query(Database).filter_by(database_name="tmp_db1").one() self.assertIsNotNone( security_manager.find_permission_view_menu("database_access", tmp_db1.perm) ) tmp_db1.database_name = "tmp_db2" - session.commit() + db.session.commit() # Assert that the old permission was updated self.assertIsNone( @@ -347,22 +342,21 @@ def test_after_update_database__perm_database_access(self): ] ) - session.delete(tmp_db1) - session.commit() + db.session.delete(tmp_db1) + db.session.commit() def test_after_update_database_rollback(self): - session = db.session tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") - session.add(tmp_db1) - session.commit() - tmp_db1 = session.query(Database).filter_by(database_name="tmp_db1").one() + db.session.add(tmp_db1) + db.session.commit() + tmp_db1 = db.session.query(Database).filter_by(database_name="tmp_db1").one() self.assertIsNotNone( security_manager.find_permission_view_menu("database_access", tmp_db1.perm) ) tmp_db1.database_name = "tmp_db2" - session.flush() + db.session.flush() # Assert that the old permission was updated self.assertIsNone( @@ -377,7 +371,7 @@ def test_after_update_database_rollback(self): ) ) - session.rollback() + db.session.rollback() self.assertIsNotNone( security_manager.find_permission_view_menu( "database_access", f"[tmp_db1].(id:{tmp_db1.id})" @@ -390,19 +384,18 @@ def test_after_update_database_rollback(self): ) ) - session.delete(tmp_db1) - session.commit() + db.session.delete(tmp_db1) + db.session.commit() def test_after_update_database__perm_database_access_exists(self): security_manager.on_permission_view_after_delete = Mock() - session = db.session # Add a bogus existing permission before the change tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") - session.add(tmp_db1) - session.commit() - tmp_db1 = session.query(Database).filter_by(database_name="tmp_db1").one() + db.session.add(tmp_db1) + db.session.commit() + tmp_db1 = db.session.query(Database).filter_by(database_name="tmp_db1").one() security_manager.add_permission_view_menu( "database_access", f"[tmp_db2].(id:{tmp_db1.id})" ) @@ -412,7 +405,7 @@ def test_after_update_database__perm_database_access_exists(self): ) tmp_db1.database_name = "tmp_db2" - session.commit() + db.session.commit() # Assert that the old permission was updated self.assertIsNone( @@ -433,41 +426,40 @@ def test_after_update_database__perm_database_access_exists(self): ] ) - session.delete(tmp_db1) - session.commit() + db.session.delete(tmp_db1) + db.session.commit() def test_after_update_database__perm_datasource_access(self): security_manager.on_view_menu_after_update = Mock() - session = db.session tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") - session.add(tmp_db1) - session.commit() + db.session.add(tmp_db1) + db.session.commit() table1 = SqlaTable( schema="tmp_schema", table_name="tmp_table1", database=tmp_db1, ) - session.add(table1) + db.session.add(table1) table2 = SqlaTable( schema="tmp_schema", table_name="tmp_table2", database=tmp_db1, ) - session.add(table2) - session.commit() + db.session.add(table2) + db.session.commit() slice1 = Slice( datasource_id=table1.id, datasource_type=DatasourceType.TABLE, datasource_name="tmp_table1", slice_name="tmp_slice1", ) - session.add(slice1) - session.commit() - slice1 = session.query(Slice).filter_by(slice_name="tmp_slice1").one() - table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() - table2 = session.query(SqlaTable).filter_by(table_name="tmp_table2").one() + db.session.add(slice1) + db.session.commit() + slice1 = db.session.query(Slice).filter_by(slice_name="tmp_slice1").one() + table1 = db.session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + table2 = db.session.query(SqlaTable).filter_by(table_name="tmp_table2").one() # assert initial perms self.assertIsNotNone( @@ -485,9 +477,9 @@ def test_after_update_database__perm_datasource_access(self): self.assertEqual(table2.perm, f"[tmp_db1].[tmp_table2](id:{table2.id})") # Refresh and update the database name - tmp_db1 = session.query(Database).filter_by(database_name="tmp_db1").one() + tmp_db1 = db.session.query(Database).filter_by(database_name="tmp_db1").one() tmp_db1.database_name = "tmp_db2" - session.commit() + db.session.commit() # Assert that the old permissions were updated self.assertIsNone( @@ -534,18 +526,17 @@ def test_after_update_database__perm_datasource_access(self): ] ) - session.delete(slice1) - session.delete(table1) - session.delete(table2) - session.delete(tmp_db1) - session.commit() + db.session.delete(slice1) + db.session.delete(table1) + db.session.delete(table2) + db.session.delete(tmp_db1) + db.session.commit() def test_after_delete_database(self): - session = db.session tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") - session.add(tmp_db1) - session.commit() - tmp_db1 = session.query(Database).filter_by(database_name="tmp_db1").one() + db.session.add(tmp_db1) + db.session.commit() + tmp_db1 = db.session.query(Database).filter_by(database_name="tmp_db1").one() database_pvm = security_manager.find_permission_view_menu( "database_access", tmp_db1.perm @@ -553,11 +544,11 @@ def test_after_delete_database(self): self.assertIsNotNone(database_pvm) role1 = Role(name="tmp_role1") role1.permissions.append(database_pvm) - session.add(role1) - session.commit() + db.session.add(role1) + db.session.commit() - session.delete(tmp_db1) - session.commit() + db.session.delete(tmp_db1) + db.session.commit() # Assert that PVM is removed from Role role1 = security_manager.find_role("tmp_role1") @@ -571,15 +562,14 @@ def test_after_delete_database(self): ) # Cleanup - session.delete(role1) - session.commit() + db.session.delete(role1) + db.session.commit() def test_after_delete_database_rollback(self): - session = db.session tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") - session.add(tmp_db1) - session.commit() - tmp_db1 = session.query(Database).filter_by(database_name="tmp_db1").one() + db.session.add(tmp_db1) + db.session.commit() + tmp_db1 = db.session.query(Database).filter_by(database_name="tmp_db1").one() database_pvm = security_manager.find_permission_view_menu( "database_access", tmp_db1.perm @@ -587,11 +577,11 @@ def test_after_delete_database_rollback(self): self.assertIsNotNone(database_pvm) role1 = Role(name="tmp_role1") role1.permissions.append(database_pvm) - session.add(role1) - session.commit() + db.session.add(role1) + db.session.commit() - session.delete(tmp_db1) - session.flush() + db.session.delete(tmp_db1) + db.session.flush() role1 = security_manager.find_role("tmp_role1") self.assertEqual(role1.permissions, []) @@ -602,7 +592,7 @@ def test_after_delete_database_rollback(self): ) ) - session.rollback() + db.session.rollback() # Test a rollback reverts everything database_pvm = security_manager.find_permission_view_menu( @@ -613,25 +603,24 @@ def test_after_delete_database_rollback(self): self.assertEqual(role1.permissions, [database_pvm]) # Cleanup - session.delete(role1) - session.delete(tmp_db1) - session.commit() + db.session.delete(role1) + db.session.delete(tmp_db1) + db.session.commit() def test_after_delete_dataset(self): security_manager.on_permission_view_after_delete = Mock() - session = db.session tmp_db = Database(database_name="tmp_db", sqlalchemy_uri="sqlite://") - session.add(tmp_db) - session.commit() + db.session.add(tmp_db) + db.session.commit() table1 = SqlaTable( schema="tmp_schema", table_name="tmp_table1", database=tmp_db, ) - session.add(table1) - session.commit() + db.session.add(table1) + db.session.commit() table1_pvm = security_manager.find_permission_view_menu( "datasource_access", f"[tmp_db].[tmp_table1](id:{table1.id})" @@ -640,15 +629,15 @@ def test_after_delete_dataset(self): role1 = Role(name="tmp_role1") role1.permissions.append(table1_pvm) - session.add(role1) - session.commit() + db.session.add(role1) + db.session.commit() # refresh - table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + table1 = db.session.query(SqlaTable).filter_by(table_name="tmp_table1").one() # Test delete - session.delete(table1) - session.commit() + db.session.delete(table1) + db.session.commit() role1 = security_manager.find_role("tmp_role1") self.assertEqual(role1.permissions, []) @@ -670,23 +659,22 @@ def test_after_delete_dataset(self): ) # cleanup - session.delete(role1) - session.delete(tmp_db) - session.commit() + db.session.delete(role1) + db.session.delete(tmp_db) + db.session.commit() def test_after_delete_dataset_rollback(self): - session = db.session tmp_db = Database(database_name="tmp_db", sqlalchemy_uri="sqlite://") - session.add(tmp_db) - session.commit() + db.session.add(tmp_db) + db.session.commit() table1 = SqlaTable( schema="tmp_schema", table_name="tmp_table1", database=tmp_db, ) - session.add(table1) - session.commit() + db.session.add(table1) + db.session.commit() table1_pvm = security_manager.find_permission_view_menu( "datasource_access", f"[tmp_db].[tmp_table1](id:{table1.id})" @@ -695,15 +683,15 @@ def test_after_delete_dataset_rollback(self): role1 = Role(name="tmp_role1") role1.permissions.append(table1_pvm) - session.add(role1) - session.commit() + db.session.add(role1) + db.session.commit() # refresh - table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + table1 = db.session.query(SqlaTable).filter_by(table_name="tmp_table1").one() # Test delete, permissions are correctly deleted - session.delete(table1) - session.flush() + db.session.delete(table1) + db.session.flush() role1 = security_manager.find_role("tmp_role1") self.assertEqual(role1.permissions, []) @@ -714,7 +702,7 @@ def test_after_delete_dataset_rollback(self): self.assertIsNone(table1_pvm) # Test rollback, permissions exist everything is correctly rollback - session.rollback() + db.session.rollback() role1 = security_manager.find_role("tmp_role1") table1_pvm = security_manager.find_permission_view_menu( "datasource_access", f"[tmp_db].[tmp_table1](id:{table1.id})" @@ -723,26 +711,25 @@ def test_after_delete_dataset_rollback(self): self.assertEqual(role1.permissions, [table1_pvm]) # cleanup - session.delete(table1) - session.delete(role1) - session.delete(tmp_db) - session.commit() + db.session.delete(table1) + db.session.delete(role1) + db.session.delete(tmp_db) + db.session.commit() def test_after_update_dataset__name_changes(self): security_manager.on_view_menu_after_update = Mock() - session = db.session tmp_db = Database(database_name="tmp_db", sqlalchemy_uri="sqlite://") - session.add(tmp_db) - session.commit() + db.session.add(tmp_db) + db.session.commit() table1 = SqlaTable( schema="tmp_schema", table_name="tmp_table1", database=tmp_db, ) - session.add(table1) - session.commit() + db.session.add(table1) + db.session.commit() slice1 = Slice( datasource_id=table1.id, @@ -750,8 +737,8 @@ def test_after_update_dataset__name_changes(self): datasource_name="tmp_table1", slice_name="tmp_slice1", ) - session.add(slice1) - session.commit() + db.session.add(slice1) + db.session.commit() table1_pvm = security_manager.find_permission_view_menu( "datasource_access", f"[tmp_db].[tmp_table1](id:{table1.id})" @@ -759,10 +746,10 @@ def test_after_update_dataset__name_changes(self): self.assertIsNotNone(table1_pvm) # refresh - table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + table1 = db.session.query(SqlaTable).filter_by(table_name="tmp_table1").one() # Test update table1.table_name = "tmp_table1_changed" - session.commit() + db.session.commit() # Test old permission does not exist old_table1_pvm = security_manager.find_permission_view_menu( @@ -778,14 +765,14 @@ def test_after_update_dataset__name_changes(self): # test dataset permission changed changed_table1 = ( - session.query(SqlaTable).filter_by(table_name="tmp_table1_changed").one() + db.session.query(SqlaTable).filter_by(table_name="tmp_table1_changed").one() ) self.assertEqual( changed_table1.perm, f"[tmp_db].[tmp_table1_changed](id:{table1.id})" ) # Test Chart permission changed - slice1 = session.query(Slice).filter_by(slice_name="tmp_slice1").one() + slice1 = db.session.query(Slice).filter_by(slice_name="tmp_slice1").one() self.assertEqual(slice1.perm, f"[tmp_db].[tmp_table1_changed](id:{table1.id})") # Assert hook is called @@ -798,24 +785,23 @@ def test_after_update_dataset__name_changes(self): ] ) # cleanup - session.delete(slice1) - session.delete(table1) - session.delete(tmp_db) - session.commit() + db.session.delete(slice1) + db.session.delete(table1) + db.session.delete(tmp_db) + db.session.commit() def test_after_update_dataset_rollback(self): - session = db.session tmp_db = Database(database_name="tmp_db", sqlalchemy_uri="sqlite://") - session.add(tmp_db) - session.commit() + db.session.add(tmp_db) + db.session.commit() table1 = SqlaTable( schema="tmp_schema", table_name="tmp_table1", database=tmp_db, ) - session.add(table1) - session.commit() + db.session.add(table1) + db.session.commit() slice1 = Slice( datasource_id=table1.id, @@ -823,14 +809,14 @@ def test_after_update_dataset_rollback(self): datasource_name="tmp_table1", slice_name="tmp_slice1", ) - session.add(slice1) - session.commit() + db.session.add(slice1) + db.session.commit() # refresh - table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + table1 = db.session.query(SqlaTable).filter_by(table_name="tmp_table1").one() # Test update table1.table_name = "tmp_table1_changed" - session.flush() + db.session.flush() # Test old permission does not exist old_table1_pvm = security_manager.find_permission_view_menu( @@ -845,7 +831,7 @@ def test_after_update_dataset_rollback(self): self.assertIsNotNone(new_table1_pvm) # Test rollback - session.rollback() + db.session.rollback() old_table1_pvm = security_manager.find_permission_view_menu( "datasource_access", f"[tmp_db].[tmp_table1](id:{table1.id})" @@ -853,26 +839,25 @@ def test_after_update_dataset_rollback(self): self.assertIsNotNone(old_table1_pvm) # cleanup - session.delete(slice1) - session.delete(table1) - session.delete(tmp_db) - session.commit() + db.session.delete(slice1) + db.session.delete(table1) + db.session.delete(tmp_db) + db.session.commit() def test_after_update_dataset__db_changes(self): - session = db.session tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") tmp_db2 = Database(database_name="tmp_db2", sqlalchemy_uri="sqlite://") - session.add(tmp_db1) - session.add(tmp_db2) - session.commit() + db.session.add(tmp_db1) + db.session.add(tmp_db2) + db.session.commit() table1 = SqlaTable( schema="tmp_schema", table_name="tmp_table1", database=tmp_db1, ) - session.add(table1) - session.commit() + db.session.add(table1) + db.session.commit() slice1 = Slice( datasource_id=table1.id, @@ -880,8 +865,8 @@ def test_after_update_dataset__db_changes(self): datasource_name="tmp_table1", slice_name="tmp_slice1", ) - session.add(slice1) - session.commit() + db.session.add(slice1) + db.session.commit() table1_pvm = security_manager.find_permission_view_menu( "datasource_access", f"[tmp_db1].[tmp_table1](id:{table1.id})" @@ -889,10 +874,10 @@ def test_after_update_dataset__db_changes(self): self.assertIsNotNone(table1_pvm) # refresh - table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + table1 = db.session.query(SqlaTable).filter_by(table_name="tmp_table1").one() # Test update table1.database = tmp_db2 - session.commit() + db.session.commit() # Test old permission does not exist table1_pvm = security_manager.find_permission_view_menu( @@ -908,36 +893,35 @@ def test_after_update_dataset__db_changes(self): # test dataset permission and schema permission changed changed_table1 = ( - session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + db.session.query(SqlaTable).filter_by(table_name="tmp_table1").one() ) self.assertEqual(changed_table1.perm, f"[tmp_db2].[tmp_table1](id:{table1.id})") self.assertEqual(changed_table1.schema_perm, f"[tmp_db2].[tmp_schema]") # Test Chart permission changed - slice1 = session.query(Slice).filter_by(slice_name="tmp_slice1").one() + slice1 = db.session.query(Slice).filter_by(slice_name="tmp_slice1").one() self.assertEqual(slice1.perm, f"[tmp_db2].[tmp_table1](id:{table1.id})") self.assertEqual(slice1.schema_perm, f"[tmp_db2].[tmp_schema]") # cleanup - session.delete(slice1) - session.delete(table1) - session.delete(tmp_db1) - session.delete(tmp_db2) - session.commit() + db.session.delete(slice1) + db.session.delete(table1) + db.session.delete(tmp_db1) + db.session.delete(tmp_db2) + db.session.commit() def test_after_update_dataset__schema_changes(self): - session = db.session tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") - session.add(tmp_db1) - session.commit() + db.session.add(tmp_db1) + db.session.commit() table1 = SqlaTable( schema="tmp_schema", table_name="tmp_table1", database=tmp_db1, ) - session.add(table1) - session.commit() + db.session.add(table1) + db.session.commit() slice1 = Slice( datasource_id=table1.id, @@ -945,8 +929,8 @@ def test_after_update_dataset__schema_changes(self): datasource_name="tmp_table1", slice_name="tmp_slice1", ) - session.add(slice1) - session.commit() + db.session.add(slice1) + db.session.commit() table1_pvm = security_manager.find_permission_view_menu( "datasource_access", f"[tmp_db1].[tmp_table1](id:{table1.id})" @@ -954,10 +938,10 @@ def test_after_update_dataset__schema_changes(self): self.assertIsNotNone(table1_pvm) # refresh - table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + table1 = db.session.query(SqlaTable).filter_by(table_name="tmp_table1").one() # Test update table1.schema = "tmp_schema_changed" - session.commit() + db.session.commit() # Test permission still exists table1_pvm = security_manager.find_permission_view_menu( @@ -967,35 +951,34 @@ def test_after_update_dataset__schema_changes(self): # test dataset schema permission changed changed_table1 = ( - session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + db.session.query(SqlaTable).filter_by(table_name="tmp_table1").one() ) self.assertEqual(changed_table1.perm, f"[tmp_db1].[tmp_table1](id:{table1.id})") self.assertEqual(changed_table1.schema_perm, f"[tmp_db1].[tmp_schema_changed]") # Test Chart schema permission changed - slice1 = session.query(Slice).filter_by(slice_name="tmp_slice1").one() + slice1 = db.session.query(Slice).filter_by(slice_name="tmp_slice1").one() self.assertEqual(slice1.perm, f"[tmp_db1].[tmp_table1](id:{table1.id})") self.assertEqual(slice1.schema_perm, f"[tmp_db1].[tmp_schema_changed]") # cleanup - session.delete(slice1) - session.delete(table1) - session.delete(tmp_db1) - session.commit() + db.session.delete(slice1) + db.session.delete(table1) + db.session.delete(tmp_db1) + db.session.commit() def test_after_update_dataset__schema_none(self): - session = db.session tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") - session.add(tmp_db1) - session.commit() + db.session.add(tmp_db1) + db.session.commit() table1 = SqlaTable( schema="tmp_schema", table_name="tmp_table1", database=tmp_db1, ) - session.add(table1) - session.commit() + db.session.add(table1) + db.session.commit() slice1 = Slice( datasource_id=table1.id, @@ -1003,8 +986,8 @@ def test_after_update_dataset__schema_none(self): datasource_name="tmp_table1", slice_name="tmp_slice1", ) - session.add(slice1) - session.commit() + db.session.add(slice1) + db.session.commit() table1_pvm = security_manager.find_permission_view_menu( "datasource_access", f"[tmp_db1].[tmp_table1](id:{table1.id})" @@ -1012,38 +995,37 @@ def test_after_update_dataset__schema_none(self): self.assertIsNotNone(table1_pvm) # refresh - table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + table1 = db.session.query(SqlaTable).filter_by(table_name="tmp_table1").one() # Test update table1.schema = None - session.commit() + db.session.commit() # refresh - table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + table1 = db.session.query(SqlaTable).filter_by(table_name="tmp_table1").one() self.assertEqual(table1.perm, f"[tmp_db1].[tmp_table1](id:{table1.id})") self.assertIsNone(table1.schema_perm) # cleanup - session.delete(slice1) - session.delete(table1) - session.delete(tmp_db1) - session.commit() + db.session.delete(slice1) + db.session.delete(table1) + db.session.delete(tmp_db1) + db.session.commit() def test_after_update_dataset__name_db_changes(self): - session = db.session tmp_db1 = Database(database_name="tmp_db1", sqlalchemy_uri="sqlite://") tmp_db2 = Database(database_name="tmp_db2", sqlalchemy_uri="sqlite://") - session.add(tmp_db1) - session.add(tmp_db2) - session.commit() + db.session.add(tmp_db1) + db.session.add(tmp_db2) + db.session.commit() table1 = SqlaTable( schema="tmp_schema", table_name="tmp_table1", database=tmp_db1, ) - session.add(table1) - session.commit() + db.session.add(table1) + db.session.commit() slice1 = Slice( datasource_id=table1.id, @@ -1051,8 +1033,8 @@ def test_after_update_dataset__name_db_changes(self): datasource_name="tmp_table1", slice_name="tmp_slice1", ) - session.add(slice1) - session.commit() + db.session.add(slice1) + db.session.commit() table1_pvm = security_manager.find_permission_view_menu( "datasource_access", f"[tmp_db1].[tmp_table1](id:{table1.id})" @@ -1060,11 +1042,11 @@ def test_after_update_dataset__name_db_changes(self): self.assertIsNotNone(table1_pvm) # refresh - table1 = session.query(SqlaTable).filter_by(table_name="tmp_table1").one() + table1 = db.session.query(SqlaTable).filter_by(table_name="tmp_table1").one() # Test update table1.table_name = "tmp_table1_changed" table1.database = tmp_db2 - session.commit() + db.session.commit() # Test old permission does not exist table1_pvm = security_manager.find_permission_view_menu( @@ -1080,7 +1062,7 @@ def test_after_update_dataset__name_db_changes(self): # test dataset permission and schema permission changed changed_table1 = ( - session.query(SqlaTable).filter_by(table_name="tmp_table1_changed").one() + db.session.query(SqlaTable).filter_by(table_name="tmp_table1_changed").one() ) self.assertEqual( changed_table1.perm, f"[tmp_db2].[tmp_table1_changed](id:{table1.id})" @@ -1088,16 +1070,16 @@ def test_after_update_dataset__name_db_changes(self): self.assertEqual(changed_table1.schema_perm, f"[tmp_db2].[tmp_schema]") # Test Chart permission changed - slice1 = session.query(Slice).filter_by(slice_name="tmp_slice1").one() + slice1 = db.session.query(Slice).filter_by(slice_name="tmp_slice1").one() self.assertEqual(slice1.perm, f"[tmp_db2].[tmp_table1_changed](id:{table1.id})") self.assertEqual(slice1.schema_perm, f"[tmp_db2].[tmp_schema]") # cleanup - session.delete(slice1) - session.delete(table1) - session.delete(tmp_db1) - session.delete(tmp_db2) - session.commit() + db.session.delete(slice1) + db.session.delete(table1) + db.session.delete(tmp_db1) + db.session.delete(tmp_db2) + db.session.commit() def test_hybrid_perm_database(self): database = Database(database_name="tmp_database3", sqlalchemy_uri="sqlite://") @@ -1123,12 +1105,11 @@ def test_hybrid_perm_database(self): db.session.commit() def test_set_perm_slice(self): - session = db.session database = Database(database_name="tmp_database", sqlalchemy_uri="sqlite://") table = SqlaTable(table_name="tmp_perm_table", database=database) - session.add(database) - session.add(table) - session.commit() + db.session.add(database) + db.session.add(table) + db.session.commit() # no schema permission slice = Slice( @@ -1137,10 +1118,10 @@ def test_set_perm_slice(self): datasource_name="tmp_perm_table", slice_name="slice_name", ) - session.add(slice) - session.commit() + db.session.add(slice) + db.session.commit() - slice = session.query(Slice).filter_by(slice_name="slice_name").one() + slice = db.session.query(Slice).filter_by(slice_name="slice_name").one() self.assertEqual(slice.perm, table.perm) self.assertEqual(slice.perm, f"[tmp_database].[tmp_perm_table](id:{table.id})") self.assertEqual(slice.schema_perm, table.schema_perm) @@ -1148,8 +1129,10 @@ def test_set_perm_slice(self): table.schema = "tmp_perm_schema" table.table_name = "tmp_perm_table_v2" - session.commit() - table = session.query(SqlaTable).filter_by(table_name="tmp_perm_table_v2").one() + db.session.commit() + table = ( + db.session.query(SqlaTable).filter_by(table_name="tmp_perm_table_v2").one() + ) self.assertEqual(slice.perm, table.perm) self.assertEqual( slice.perm, f"[tmp_database].[tmp_perm_table_v2](id:{table.id})" @@ -1160,11 +1143,11 @@ def test_set_perm_slice(self): self.assertEqual(slice.schema_perm, table.schema_perm) self.assertEqual(slice.schema_perm, "[tmp_database].[tmp_perm_schema]") - session.delete(slice) - session.delete(table) - session.delete(database) + db.session.delete(slice) + db.session.delete(table) + db.session.delete(database) - session.commit() + db.session.commit() @patch("superset.utils.core.g") @patch("superset.security.manager.g") @@ -1192,37 +1175,31 @@ def test_schemas_accessible_by_user_schema_access(self, mock_sm_g, mock_g): self.assertEqual(schemas, ["1"]) delete_schema_perm("[examples].[1]") - @patch("superset.utils.core.g") - @patch("superset.security.manager.g") - def test_schemas_accessible_by_user_datasource_access(self, mock_sm_g, mock_g): + def test_schemas_accessible_by_user_datasource_access(self): # User has schema access to the datasource temp_schema.wb_health_population in examples DB. - mock_g.user = mock_sm_g.user = security_manager.find_user("gamma") + database = get_example_database() with self.client.application.test_request_context(): - database = get_example_database() - schemas = security_manager.get_schemas_accessible_by_user( - database, ["temp_schema", "2", "3"] - ) - self.assertEqual(schemas, ["temp_schema"]) + with override_user(security_manager.find_user("gamma")): + schemas = security_manager.get_schemas_accessible_by_user( + database, ["temp_schema", "2", "3"] + ) + self.assertEqual(schemas, ["temp_schema"]) - @patch("superset.utils.core.g") - @patch("superset.security.manager.g") - def test_schemas_accessible_by_user_datasource_and_schema_access( - self, mock_sm_g, mock_g - ): + def test_schemas_accessible_by_user_datasource_and_schema_access(self): # User has schema access to the datasource temp_schema.wb_health_population in examples DB. create_schema_perm("[examples].[2]") - mock_g.user = mock_sm_g.user = security_manager.find_user("gamma") with self.client.application.test_request_context(): database = get_example_database() - schemas = security_manager.get_schemas_accessible_by_user( - database, ["temp_schema", "2", "3"] - ) - self.assertEqual(schemas, ["temp_schema", "2"]) - vm = security_manager.find_permission_view_menu( - "schema_access", "[examples].[2]" - ) - self.assertIsNotNone(vm) - delete_schema_perm("[examples].[2]") + with override_user(security_manager.find_user("gamma")): + schemas = security_manager.get_schemas_accessible_by_user( + database, ["temp_schema", "2", "3"] + ) + self.assertEqual(schemas, ["temp_schema", "2"]) + vm = security_manager.find_permission_view_menu( + "schema_access", "[examples].[2]" + ) + self.assertIsNotNone(vm) + delete_schema_perm("[examples].[2]") @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices") def test_gamma_user_schema_access_to_dashboards(self): @@ -1279,10 +1256,11 @@ def test_public_sync_role_builtin_perms(self): @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices") def test_sqllab_gamma_user_schema_access_to_sqllab(self): - session = db.session - example_db = session.query(Database).filter_by(database_name="examples").one() + example_db = ( + db.session.query(Database).filter_by(database_name="examples").one() + ) example_db.expose_in_sqllab = True - session.commit() + db.session.commit() arguments = { "keys": ["none"], @@ -1642,25 +1620,42 @@ def test_raise_for_access_query(self, mock_can_access, mock_is_owner): with self.assertRaises(SupersetSecurityException): security_manager.raise_for_access(query=query) - @patch("superset.security.manager.g") + def test_raise_for_access_sql_fails(self): + with override_user(security_manager.find_user("gamma")): + with self.assertRaises(SupersetSecurityException): + security_manager.raise_for_access( + database=get_example_database(), + schema="bar", + sql="SELECT * FROM foo", + ) + + @patch("superset.security.SupersetSecurityManager.is_owner") + @patch("superset.security.SupersetSecurityManager.can_access") + def test_raise_for_access_sql(self, mock_can_access, mock_is_owner): + mock_can_access.return_value = True + mock_is_owner.return_value = True + with override_user(security_manager.find_user("gamma")): + security_manager.raise_for_access( + database=get_example_database(), schema="bar", sql="SELECT * FROM foo" + ) + @patch("superset.security.SupersetSecurityManager.is_owner") @patch("superset.security.SupersetSecurityManager.can_access") @patch("superset.security.SupersetSecurityManager.can_access_schema") def test_raise_for_access_query_context( - self, mock_can_access_schema, mock_can_access, mock_is_owner, mock_g + self, mock_can_access_schema, mock_can_access, mock_is_owner ): query_context = Mock(datasource=self.get_datasource_mock(), form_data={}) mock_can_access_schema.return_value = True security_manager.raise_for_access(query_context=query_context) - mock_g.user = security_manager.find_user("gamma") mock_can_access.return_value = False mock_can_access_schema.return_value = False mock_is_owner.return_value = False - - with self.assertRaises(SupersetSecurityException): - security_manager.raise_for_access(query_context=query_context) + with override_user(security_manager.find_user("gamma")): + with self.assertRaises(SupersetSecurityException): + security_manager.raise_for_access(query_context=query_context) @patch("superset.security.SupersetSecurityManager.can_access") def test_raise_for_access_table(self, mock_can_access): @@ -1675,30 +1670,27 @@ def test_raise_for_access_table(self, mock_can_access): with self.assertRaises(SupersetSecurityException): security_manager.raise_for_access(database=database, table=table) - @patch("superset.security.manager.g") @patch("superset.security.SupersetSecurityManager.is_owner") @patch("superset.security.SupersetSecurityManager.can_access") @patch("superset.security.SupersetSecurityManager.can_access_schema") def test_raise_for_access_viz( - self, mock_can_access_schema, mock_can_access, mock_is_owner, mock_g + self, mock_can_access_schema, mock_can_access, mock_is_owner ): test_viz = viz.TimeTableViz(self.get_datasource_mock(), form_data={}) mock_can_access_schema.return_value = True security_manager.raise_for_access(viz=test_viz) - mock_g.user = security_manager.find_user("gamma") mock_can_access.return_value = False mock_can_access_schema.return_value = False mock_is_owner.return_value = False - - with self.assertRaises(SupersetSecurityException): - security_manager.raise_for_access(viz=test_viz) + with override_user(security_manager.find_user("gamma")): + with self.assertRaises(SupersetSecurityException): + security_manager.raise_for_access(viz=test_viz) @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @pytest.mark.usefixtures("load_world_bank_dashboard_with_slices") @with_feature_flags(DASHBOARD_RBAC=True) - @patch("superset.security.manager.g") @patch("superset.security.SupersetSecurityManager.is_owner") @patch("superset.security.SupersetSecurityManager.can_access") @patch("superset.security.SupersetSecurityManager.can_access_schema") @@ -1707,7 +1699,6 @@ def test_raise_for_access_rbac( mock_can_access_schema, mock_can_access, mock_is_owner, - mock_g, ): births = self.get_dash_by_slug("births") girls = self.get_slice("Girls", db.session, expunge_from_session=False) @@ -1731,161 +1722,156 @@ def test_raise_for_access_rbac( } ) - mock_g.user = security_manager.find_user("gamma") mock_is_owner.return_value = False mock_can_access.return_value = False mock_can_access_schema.return_value = False + with override_user(security_manager.find_user("gamma")): + for kwarg in ["query_context", "viz"]: + births.roles = [] + + # No dashboard roles. + with self.assertRaises(SupersetSecurityException): + security_manager.raise_for_access( + **{ + kwarg: Mock( + datasource=birth_names, + form_data={ + "dashboardId": births.id, + "slice_id": girls.id, + }, + ) + } + ) - for kwarg in ["query_context", "viz"]: - births.roles = [] - - # No dashboard roles. - with self.assertRaises(SupersetSecurityException): - security_manager.raise_for_access( - **{ - kwarg: Mock( - datasource=birth_names, - form_data={ - "dashboardId": births.id, - "slice_id": girls.id, - }, - ) - } - ) + births.roles = [self.get_role("Gamma")] + + # Undefined dashboard. + with self.assertRaises(SupersetSecurityException): + security_manager.raise_for_access( + **{ + kwarg: Mock( + datasource=birth_names, + form_data={}, + ) + } + ) - births.roles = [self.get_role("Gamma")] + # Undefined dashboard chart. + with self.assertRaises(SupersetSecurityException): + security_manager.raise_for_access( + **{ + kwarg: Mock( + datasource=birth_names, + form_data={"dashboardId": births.id}, + ) + } + ) - # Undefined dashboard. - with self.assertRaises(SupersetSecurityException): - security_manager.raise_for_access( - **{ - kwarg: Mock( - datasource=birth_names, - form_data={}, - ) - } - ) + # Ill-defined dashboard chart. + with self.assertRaises(SupersetSecurityException): + security_manager.raise_for_access( + **{ + kwarg: Mock( + datasource=birth_names, + form_data={ + "dashboardId": births.id, + "slice_id": treemap.id, + }, + ) + } + ) - # Undefined dashboard chart. - with self.assertRaises(SupersetSecurityException): - security_manager.raise_for_access( - **{ - kwarg: Mock( - datasource=birth_names, - form_data={"dashboardId": births.id}, - ) - } - ) + # Dashboard chart not associated with said datasource. + with self.assertRaises(SupersetSecurityException): + security_manager.raise_for_access( + **{ + kwarg: Mock( + datasource=birth_names, + form_data={ + "dashboardId": world_health.id, + "slice_id": treemap.id, + }, + ) + } + ) - # Ill-defined dashboard chart. - with self.assertRaises(SupersetSecurityException): + # Dashboard chart associated with said datasource. security_manager.raise_for_access( **{ kwarg: Mock( datasource=birth_names, form_data={ "dashboardId": births.id, - "slice_id": treemap.id, - }, - ) - } - ) - - # Dashboard chart not associated with said datasource. - with self.assertRaises(SupersetSecurityException): - security_manager.raise_for_access( - **{ - kwarg: Mock( - datasource=birth_names, - form_data={ - "dashboardId": world_health.id, - "slice_id": treemap.id, + "slice_id": girls.id, }, ) } ) - # Dashboard chart associated with said datasource. - security_manager.raise_for_access( - **{ - kwarg: Mock( - datasource=birth_names, - form_data={ - "dashboardId": births.id, - "slice_id": girls.id, - }, + # Ill-defined native filter. + with self.assertRaises(SupersetSecurityException): + security_manager.raise_for_access( + **{ + kwarg: Mock( + datasource=birth_names, + form_data={ + "dashboardId": births.id, + "type": "NATIVE_FILTER", + }, + ) + } ) - } - ) - # Ill-defined native filter. - with self.assertRaises(SupersetSecurityException): - security_manager.raise_for_access( - **{ - kwarg: Mock( - datasource=birth_names, - form_data={ - "dashboardId": births.id, - "type": "NATIVE_FILTER", - }, - ) - } - ) + # Native filter not associated with said datasource. + with self.assertRaises(SupersetSecurityException): + security_manager.raise_for_access( + **{ + kwarg: Mock( + datasource=birth_names, + form_data={ + "dashboardId": births.id, + "native_filter_id": "NATIVE_FILTER-IJKLMNOP", + "type": "NATIVE_FILTER", + }, + ) + } + ) - # Native filter not associated with said datasource. - with self.assertRaises(SupersetSecurityException): + # Native filter associated with said datasource. security_manager.raise_for_access( **{ kwarg: Mock( datasource=birth_names, form_data={ "dashboardId": births.id, - "native_filter_id": "NATIVE_FILTER-IJKLMNOP", + "native_filter_id": "NATIVE_FILTER-ABCDEFGH", "type": "NATIVE_FILTER", }, ) } ) - # Native filter associated with said datasource. - security_manager.raise_for_access( - **{ - kwarg: Mock( - datasource=birth_names, - form_data={ - "dashboardId": births.id, - "native_filter_id": "NATIVE_FILTER-ABCDEFGH", - "type": "NATIVE_FILTER", - }, - ) - } - ) - - db.session.expunge_all() + db.session.expunge_all() - @patch("superset.security.manager.g") - def test_get_user_roles(self, mock_g): + def test_get_user_roles(self): admin = security_manager.find_user("admin") - mock_g.user = admin - roles = security_manager.get_user_roles() - self.assertEqual(admin.roles, roles) + with override_user(admin): + roles = security_manager.get_user_roles() + self.assertEqual(admin.roles, roles) - @patch("superset.security.manager.g") - def test_get_anonymous_roles(self, mock_g): - mock_g.user = security_manager.get_anonymous_user() - roles = security_manager.get_user_roles() - self.assertEqual([security_manager.get_public_role()], roles) + def test_get_anonymous_roles(self): + with override_user(security_manager.get_anonymous_user()): + roles = security_manager.get_user_roles() + self.assertEqual([security_manager.get_public_role()], roles) class TestDatasources(SupersetTestCase): - @patch("superset.security.manager.g") @patch("superset.security.SupersetSecurityManager.can_access_database") @patch("superset.security.SupersetSecurityManager.get_session") def test_get_user_datasources_admin( - self, mock_get_session, mock_can_access_database, mock_g + self, mock_get_session, mock_can_access_database ): Datasource = namedtuple("Datasource", ["database", "schema", "name"]) - mock_g.user = security_manager.find_user("admin") mock_can_access_database.return_value = True mock_get_session.query.return_value.filter.return_value.all.return_value = [] @@ -1897,23 +1883,20 @@ def test_get_user_datasources_admin( Datasource("database1", "schema1", "table2"), Datasource("database2", None, "table1"), ] + with override_user(security_manager.find_user("admin")): + datasources = security_manager.get_user_datasources() + assert sorted(datasources) == [ + Datasource("database1", "schema1", "table1"), + Datasource("database1", "schema1", "table2"), + Datasource("database2", None, "table1"), + ] - datasources = security_manager.get_user_datasources() - - assert sorted(datasources) == [ - Datasource("database1", "schema1", "table1"), - Datasource("database1", "schema1", "table2"), - Datasource("database2", None, "table1"), - ] - - @patch("superset.security.manager.g") @patch("superset.security.SupersetSecurityManager.can_access_database") @patch("superset.security.SupersetSecurityManager.get_session") def test_get_user_datasources_gamma( - self, mock_get_session, mock_can_access_database, mock_g + self, mock_get_session, mock_can_access_database ): Datasource = namedtuple("Datasource", ["database", "schema", "name"]) - mock_g.user = security_manager.find_user("gamma") mock_can_access_database.return_value = False mock_get_session.query.return_value.filter.return_value.all.return_value = [] @@ -1925,19 +1908,16 @@ def test_get_user_datasources_gamma( Datasource("database1", "schema1", "table2"), Datasource("database2", None, "table1"), ] + with override_user(security_manager.find_user("gamma")): + datasources = security_manager.get_user_datasources() + assert datasources == [] - datasources = security_manager.get_user_datasources() - - assert datasources == [] - - @patch("superset.security.manager.g") @patch("superset.security.SupersetSecurityManager.can_access_database") @patch("superset.security.SupersetSecurityManager.get_session") def test_get_user_datasources_gamma_with_schema( - self, mock_get_session, mock_can_access_database, mock_g + self, mock_get_session, mock_can_access_database ): Datasource = namedtuple("Datasource", ["database", "schema", "name"]) - mock_g.user = security_manager.find_user("gamma") mock_can_access_database.return_value = False mock_get_session.query.return_value.filter.return_value.all.return_value = [ @@ -1953,13 +1933,12 @@ def test_get_user_datasources_gamma_with_schema( Datasource("database1", "schema1", "table2"), Datasource("database2", None, "table1"), ] - - datasources = security_manager.get_user_datasources() - - assert sorted(datasources) == [ - Datasource("database1", "schema1", "table1"), - Datasource("database1", "schema1", "table2"), - ] + with override_user(security_manager.find_user("gamma")): + datasources = security_manager.get_user_datasources() + assert sorted(datasources) == [ + Datasource("database1", "schema1", "table1"), + Datasource("database1", "schema1", "table2"), + ] class FakeRequest: diff --git a/tests/unit_tests/common/test_query_object_factory.py b/tests/unit_tests/common/test_query_object_factory.py index 02304828dca82..590ace3f10fb6 100644 --- a/tests/unit_tests/common/test_query_object_factory.py +++ b/tests/unit_tests/common/test_query_object_factory.py @@ -38,11 +38,6 @@ def app_config() -> dict[str, Any]: return create_app_config().copy() -@fixture -def session_factory() -> Mock: - return Mock() - - @fixture def connector_registry() -> Mock: return Mock(spec=["get_datasource"]) @@ -58,12 +53,12 @@ def apply_max_row_limit(limit: int, max_limit: Optional[int] = None) -> int: @fixture def query_object_factory( - app_config: dict[str, Any], connector_registry: Mock, session_factory: Mock + app_config: dict[str, Any], connector_registry: Mock ) -> QueryObjectFactory: import superset.common.query_object_factory as mod mod.apply_max_row_limit = apply_max_row_limit - return QueryObjectFactory(app_config, connector_registry, session_factory) + return QueryObjectFactory(app_config, connector_registry) @fixture diff --git a/tests/unit_tests/conftest.py b/tests/unit_tests/conftest.py index 4444fdc8c7564..beb4e99472c19 100644 --- a/tests/unit_tests/conftest.py +++ b/tests/unit_tests/conftest.py @@ -172,7 +172,6 @@ def dummy_query_object(request, app_context): "ROW_LIMIT": 100, }, _datasource_dao=unittest.mock.Mock(), - session_maker=unittest.mock.Mock(), ).create(parent_result_type=result_type, **query_object) diff --git a/tests/unit_tests/datasource/dao_tests.py b/tests/unit_tests/datasource/dao_tests.py index 0af2cbf0200bf..b4ce162c0c0c9 100644 --- a/tests/unit_tests/datasource/dao_tests.py +++ b/tests/unit_tests/datasource/dao_tests.py @@ -106,7 +106,6 @@ def test_get_datasource_sqlatable(session_with_data: Session) -> None: result = DatasourceDAO.get_datasource( datasource_type=DatasourceType.TABLE, datasource_id=1, - session=session_with_data, ) assert 1 == result.id @@ -119,7 +118,7 @@ def test_get_datasource_query(session_with_data: Session) -> None: from superset.models.sql_lab import Query result = DatasourceDAO.get_datasource( - datasource_type=DatasourceType.QUERY, datasource_id=1, session=session_with_data + datasource_type=DatasourceType.QUERY, datasource_id=1 ) assert result.id == 1 @@ -133,7 +132,6 @@ def test_get_datasource_saved_query(session_with_data: Session) -> None: result = DatasourceDAO.get_datasource( datasource_type=DatasourceType.SAVEDQUERY, datasource_id=1, - session=session_with_data, ) assert result.id == 1 @@ -147,7 +145,6 @@ def test_get_datasource_sl_table(session_with_data: Session) -> None: result = DatasourceDAO.get_datasource( datasource_type=DatasourceType.SLTABLE, datasource_id=1, - session=session_with_data, ) assert result.id == 1 @@ -161,7 +158,6 @@ def test_get_datasource_sl_dataset(session_with_data: Session) -> None: result = DatasourceDAO.get_datasource( datasource_type=DatasourceType.DATASET, datasource_id=1, - session=session_with_data, ) assert result.id == 1 @@ -178,7 +174,6 @@ def test_get_datasource_w_str_param(session_with_data: Session) -> None: DatasourceDAO.get_datasource( datasource_type="table", datasource_id=1, - session=session_with_data, ), SqlaTable, ) @@ -187,7 +182,6 @@ def test_get_datasource_w_str_param(session_with_data: Session) -> None: DatasourceDAO.get_datasource( datasource_type="sl_table", datasource_id=1, - session=session_with_data, ), Table, ) @@ -208,5 +202,4 @@ def test_not_found_datasource(session_with_data: Session) -> None: DatasourceDAO.get_datasource( datasource_type="table", datasource_id=500000, - session=session_with_data, ) diff --git a/tests/unit_tests/db_engine_specs/test_trino.py b/tests/unit_tests/db_engine_specs/test_trino.py index df1457dcad7d4..308902c9016cd 100644 --- a/tests/unit_tests/db_engine_specs/test_trino.py +++ b/tests/unit_tests/db_engine_specs/test_trino.py @@ -24,11 +24,19 @@ import pandas as pd import pytest from pytest_mock import MockerFixture +from requests.exceptions import ConnectionError as RequestsConnectionError from sqlalchemy import types +from trino.exceptions import TrinoExternalError, TrinoInternalError, TrinoUserError from trino.sqlalchemy import datatype import superset.config from superset.constants import QUERY_CANCEL_KEY, QUERY_EARLY_CANCEL_KEY, USER_AGENT +from superset.db_engine_specs.exceptions import ( + SupersetDBAPIConnectionError, + SupersetDBAPIDatabaseError, + SupersetDBAPIOperationalError, + SupersetDBAPIProgrammingError, +) from superset.superset_typing import ResultSetColumnType, SQLAColumnType from superset.utils.core import GenericDataType from tests.unit_tests.db_engine_specs.utils import ( @@ -529,3 +537,14 @@ def test_get_indexes_no_table(): db_mock, inspector_mock, "test_table", "test_schema" ) assert result == [] + + +def test_get_dbapi_exception_mapping(): + from superset.db_engine_specs.trino import TrinoEngineSpec + + mapping = TrinoEngineSpec.get_dbapi_exception_mapping() + assert mapping.get(TrinoUserError) == SupersetDBAPIProgrammingError + assert mapping.get(TrinoInternalError) == SupersetDBAPIDatabaseError + assert mapping.get(TrinoExternalError) == SupersetDBAPIOperationalError + assert mapping.get(RequestsConnectionError) == SupersetDBAPIConnectionError + assert mapping.get(Exception) is None